I am using Angular 2.0.0-alpha.30 version. When redirect to a different route, then refresh the browser , its showing Cannot GET /route.

Can you help me with figuring why this error happened.

1 upvote
  flag
upvote
  flag
Thanks for the reply but that one is for angular 1.x versions . I am facing the issue in angular 2.0. – Vinz and Tonz
1 upvote
  flag
The linked question is a general problem with pushState not Angular specific. Your question doesn't provide enough information to know if it is related. – Günter Zöchbauer
2 upvote
  flag
Angular 2.0 uses a completely new router so the linked post is of no use now since its the old router – Vinz and Tonz
upvote
  flag
As I said if it is the pushState issue it is not Angular specific and can't be fixed by Angular but needs to be fixed on the server instead. – Günter Zöchbauer
upvote
  flag
some server configuration is needed, have a look at this post for some more details (added answer bellow). its not advised to switch to the hash location strategy blog.angular-university.io/angular2-router – Angular University

24 Answers 11

I think the error you are seeing is because your are requesting http://localhost/route which doesn't exist. You need to make sure that your server will map all requests to your main index.html page.

As Angular 2 uses html5 routing by default rather than using hashes at the end of the url, refreshing the page looks like a request for a different resource.

5 upvote
  flag
so how do we fix that? how do we map all requests to main index by default? is it server-reliant? – Ayyash
1 upvote
  flag
Yes, you would do this on the server with whatever web framework you are using. The alternative is to use the HashLocationStrategy as described below. – Simon
upvote
  flag
You will be reloading the angular SPA in every non present route. Is it how it should be handled? – Gary
upvote
  flag
It only reloads if the user clicks refresh on the browser, not when user changes routes through the UI. Not really any way around a reload when the user refreshes. – user2748659

Disclaimer: this fix works with Alpha44

I had the same issue and solved it by implementing the HashLocationStrategy listed in the Angular.io API Preview.

https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html

Start by importing the necessary directives

import {provide} from 'angular2/angular2';
import {
  ROUTER_PROVIDERS,
  LocationStrategy,
  HashLocationStrategy
} from 'angular2/router';

And finally, bootstrap it all together like so

bootstrap(AppCmp, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

Your route will appear as http://localhost/#/route and when you refresh, it will reload at it's proper place.

Hope that helps!

upvote
  flag
this code will work fine but there is someProblem in this technique by using this # will added automaticaly in the URL. is there any solution to remove # from the URL by using this ? – Pardeep Jain
upvote
  flag
Agreed, I tried implementing the "PathLocationStrategy" listed here, but couldn't get it to work. A URL without the # would be optimal. – SimonHawesome
upvote
  flag
Yes me too tried the same with the PathLocationStrategy but this is not working for me. either i used wrong method or either i dont know how to use PathLocationStrategy. – Pardeep Jain
1 upvote
  flag
This doesn't work for me in RC1. Importing LocationStrategy, HashLocationStrategy from '@angular/router' fails. – psych
upvote
  flag
@psych As indicated in the disclaimer, the solution I provided works for Alpha 44. This issue has since been fixed as of (RC.3). See Günter Zöchbauer's answer, apart of this thread. – SimonHawesome
upvote
  flag
We use github.com/mgechev/angular2-seed and the current version (based on angular2 rc.5) incorporates this. However it was not in the version based on rc.4. – HankCa
upvote
  flag
Sorry for coming back to this questions after more than 1 year :) But does HashLocationStrategy help stay on the same Router path? In my case when I refresh it takes me to localhost/#/<default route> i.e the default route for the home page. How do I go to the current route that I was originally on when I 'Refreshed'? – rajugaadu

Simon's answer was correct for me. I added this code:

app.get('*', function(req, res, next) {
  res.sendfile("dist/index.html");
});
upvote
  flag
express file ? if you have pls provide plnkr for your code it will helps to understand better. – Pardeep Jain
upvote
  flag
this is not related with angular – Branislav Djuric
upvote
  flag
@BranislavDjuric It's not, but it does solve the problem for anyone using node.js and express. – Hector
upvote
  flag
What happens when an image request comes in for an image that does not exist on disk? they get the index.html back? – JBeckton
up vote 101 down vote accepted

The error you are seeing is because you are requesting http://localhost/route which doesn't exist. According to Simon.

When using html5 routing you need to map all routes in your app(currently 404) to index.html in your server side. Here are some options for you:

  1. using live-server: https://www.npmjs.com/package/live-server

    $live-server --entry-file=index.html

  2. using nginx: http://nginx.org/en/docs/beginners_guide.html

    error_page 404 /index.html

  3. Tomcat - configuration of web.xml. From Kunin's comment

    <error-page> <error-code>404</error-code> <location>/index.html</location> </error-page>

1 upvote
  flag
Since one needs server side support for html5 routing this works perfectly well. Thanx – Prabhat
8 upvote
  flag
Who down voted me? :sosad: – Quy Tang
3 upvote
  flag
This worked perfectly for me, thanks! – Kris
upvote
  flag
Can I use nginx as a proxy to pub serve? That way I don't need to pub build a lot during development. I tried but proxy_pass doesn't work very well with error_page. – Franklin Yu
upvote
  flag
@FranklinYu I haven't done it before. Do you get it resolved? – Quy Tang
upvote
  flag
Not yet. I thought the argument uri of error_page can be something like localhost:8000/index.html, but it didn't work. The example on the documentation hint that I can "pass error processing into a named location", but it didn't seem to work for me either. – Franklin Yu
1 upvote
  flag
Using nginx. , error_page 404 /index.html in the location of the app worked for me. Thank you. – Richard K. Campion
upvote
  flag
Using nginx. This works but then still displays a 404 in my browser console. Any workaround? – Bob
upvote
  flag
@RichardK.Campion //allinonescript.com/a/19489441/2463695. You can click at edited to view the old answer version – Quy Tang
upvote
  flag
@flash that's why I wrote: error_page 404 =200 /index.html. – Quy Tang
upvote
  flag
How can I fix that, if I'm using ng build to generate my app? – Braulio Soncco
1 upvote
  flag
Tomcat - configuration of web.xml <error-page> <error-code>404</error-code> <location>/index.html</location> </error-page> – A Kunin

Make sure this is placed in the head element of your index.html:

<base href="/">

The Example in the Angular2 Routing & Navigation documentation uses the following code in the head instead (they explain why in the live example note of the documentation):

<script>document.write('<base href="' + document.location + '" />');</script>

When you refresh a page this will dynamically set the base href to your current document.location. I could see this causing some confusion for people skimming the documentation and trying to replicate the plunker.

upvote
  flag
Perfect solution, man. Thank you a lot! – Henrique Rotava
upvote
  flag
Thanks for sharing this. Let's just be clear, it only worked for me when I put <base href="/"> directly after loading all css in the <head>, and before loading ANY Js files . I hope it helps anyone – wmehanna

Server configuration is not a solution for an SPA is what even I think. You dont want to reload an angular SPA again if a wrong route comes in, do you? So I will not depend on a server route and redirect to other route but yes I will let index.html handle all the requests for angular routes of the angular app path.

Try this instead of otherwise or wrong routes. It works for me, not sure but seems like work in progress. Stumbled this myself when facing an issue.

@RouteConfig([
  { path: '/**', redirectTo: ['MycmpnameCmp'] }, 
   ...
  }
])

https://github.com/angular/angular/issues/4055

However remember to configure your server folders and access right in case you have HTML or web scripts which are not SPA. Else you will face issues. For me when facing issue like you it was a mix of server configuration and above.

Angular by default uses HTML5 pushstate (PathLocationStrategy in Angular slang).
You either need a server that processes all requests like it were requesting index.html or you switch to HashLocationStrategy (with # in the URL for routes) https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html

See also https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/

To switch to HashLocationStrategy use

update for >= RC.5 and 2.0.0 final

import {HashLocationStrategy, LocationStrategy} from '@angular/common';

@NgModule({
  declarations: [AppCmp], 
  bootstrap: [AppCmp],
  imports: [BrowserModule, routes],
  providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
]);

or shorter with useHash

imports: [RouterModule.forRoot(ROUTER_CONFIG, {useHash: true}), ...

ensure you have all required imports

For the new (RC.3) router

<base href="."> 

can cause 404 as well.

It requires instead

<base href="/">

update for >= RC.x

bootstrap(AppCmp, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
  // or since RC.2
  {provide: LocationStrategy, useClass: HashLocationStrategy} 
]);

import {provide} from '@angular/core';
import {  
  PlatformLocation,  
  Location,  
  LocationStrategy,  
  HashLocationStrategy,  
  PathLocationStrategy,  
  APP_BASE_HREF}  
from '@angular/common';  

update for >= beta.16 Imports have changed

import {BrowserPlatformLocation} from '@angular/platform-browser';

import {provide} from 'angular2/core';
import {
  // PlatformLocation,
  // Location,
  LocationStrategy,
  HashLocationStrategy,
  // PathLocationStrategy,
  APP_BASE_HREF}
from 'angular2/router';
import {BrowserPlatformLocation} from 'angular2/src/router/location/browser_platform_location';

< beta.16

import {provide} from 'angular2/core';
import {
  HashLocationStrategy
  LocationStrategy,
  ROUTER_PROVIDERS,
} from 'angular2/router';

See also https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta16-2016-04-26 breaking-changes

1 upvote
  flag
Thanks! provide seems to have moved under angular/core: import {provide} from 'angular2/core' – StrangeLoop
upvote
  flag
@StrangeLoop thanks a lot - fixed. – Günter Zöchbauer
1 upvote
  flag
Just to note: update for >= RC.x (RC.2) works with router 3.0.0-alpha.7, but provide annotated as deprecated without information about which function replaced it. – Mrusful
upvote
  flag
Use {provide: SomeClass, useClass: OtherClass} – Günter Zöchbauer
1 upvote
  flag
Most updated answer. For the latest version of angular 2.4.1 I had <base href="./"> . Changed into <base href="/"> solved the issue I had. Might be helpful for someone. – Saiyaff Farouk

This is a common situation in all router versions if you are using the default HTML location strategy.

What happens is that the URL on the browser bar is a normal full HTML url, like for example: http://localhost/route.

So when we hit Enter in the browser bar, there is an actual HTTP request sent to the server to get a file named route.

The server does not have such file, and neither something like express is configured on the server to handle the request and provide a response, so the server return 404 Not Found, because it could not find the route file.

What we would like is for the server to return the index.html file containing the single page application. Then the router should kick in and process the /route url and display the component mapped to it.

So to fix the issue we need to configure the server to return index.html (assuming that is the name of your single page application file) in case the request could not be handled, as opposed to a 404 Not Found.

The way to do this will depend on the server side technology being used. If its Java for example you might have to write a servlet, in Rails it will be different, etc.

To give a concrete example, if for example you are using NodeJs, you would have to write a middleware like this:

function sendSpaFileIfUnmatched(req,res) {
    res.sendFile("index.html", { root: '.' });
}

And then register it at the very end of the middleware chain:

app.use(sendSpaFileIfUnmatched);

This will serve index.html instead of returning a 404, the router will kick in and everything will work as expected.

upvote
  flag
This was exactly my issue. If you use NGINX, this answer helps resolve it: //allinonescript.com/questions/7027636/… – Nathan
upvote
  flag
What happens with unresolved images etc? – Richard Peck
upvote
  flag
Is there a tutorial on how to do this for java? Thanks. – 000000000000000000000

For those of us struggling through life in IIS: use the following PowerShell code to fix this issue based on the official Angular 2 docs (that someone posted in this thread? http://blog.angular-university.io/angular2-router/)

Import-WebAdministration
# Grab the 404 handler and update it to redirect to index.html.
$redirect = Get-WebConfiguration -filter "/system.WebServer/httperrors/error[@statusCode='404']" -PSPath IIS:\Sites\LIS 
$redirect.path = "/index.html"
$redirect.responseMode = 1
# shove the updated config back into IIS
Set-WebConfiguration -filter "/system.WebServer/httperrors/error[@statusCode='404']" -PSPath IIS:\Sites\LIS -value $redirect

This redirects the 404 to the /index.html file as per the suggestion in the Angular 2 docs (link above).

I had the same problem with using webpack-dev-server. I had to add the devServer option to my webpack.

Solution:

// in webpack
devServer: {
    historyApiFallback: true,
    stats: 'minimal'
}
upvote
  flag
Kind of voodoo magic :p For more info, see : webpack.github.io/docs/… – Jissay
upvote
  flag
that's was perfect, it works for me thanks – poa

I wanted to preserve the URL path of sub pages in HTML5 mode without a redirect back to index and none of the solutions out there told me how to do this, so this is how I accomplished it:

Create simple virtual directories in IIS for all your routes and point them to the app root.

Wrap your system.webServer in your Web.config.xml with this location tag, otherwise you will get duplicate errors from it loading Web.config a second time with the virtual directory:

<configuration>
    <location path="." inheritInChildApplications="false">
    <system.webServer>
        <defaultDocument enabled="true">
            <files>
                <add value="index.html" />
            </files>
        </defaultDocument>
    </system.webServer>
  </location>
</configuration>

I checked in angular 2 seed how it works.

You can use express-history-api-fallback to redirect automatically when a page is reload.

I think it's the most elegant way to resolve this problem IMO.

This is not the right answer but On-refresh you can redirect all dead calls to Homepage by sacrificing 404 page it's a temporary hack just replay following on 404.html file

<!doctype html>
<html>
    <head>
        <script type="text/javascript">
            window.location.href = "http://" + document.location.host;
        </script>
    </head>
</html>

If you want to be able to enter urls in browser without configuring your AppServer to handle all requests to index.html, you must use HashLocationStrategy.

The easiest way to configure is using:

RouterModule.forRoot(routes, { useHash: true })

Instead of:

RouterModule.forRoot(routes)

With HashLocationStrategy your urls gonna be like:

http://server:port/#/path

If you are using Apache as a server you have to create a .htaccess (if not created before) and "On" RewriteEngine


    RewriteEngine On  
      RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
      RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
      RewriteRule ^ - [L]
      RewriteRule ^ /index.html

My server is Apache, what I did to fix 404 when refreshing or deep linking is very simple. Just add one line in apache vhost config:

ErrorDocument 404 /index.html

So that any 404 error will be redirected to index.html, which is what angular2 routing wants.

The whole vhost file example:

<VirtualHost *:80>

  ServerName fenz.niwa.local

  DirectoryIndex index.html

  ErrorDocument 404 /index.html

  DocumentRoot "/Users/zhoum/Documents/workspace/fire/fire_service/dist"

  ErrorLog /Users/zhoum/Documents/workspace/fire/fire_service/logs/fenz.error.log

  CustomLog /Users/zhoum/Documents/workspace/fire/fire_service/logs/fenz.access.log combined




  <Directory "/Users/zhoum/Documents/workspace/fire/fire_service/dist">

    AllowOverride All

    Options Indexes FollowSymLinks

    #Order allow,deny

    #Allow from All

    Require all granted

  </Directory>




  Header set Access-Control-Allow-Origin "*"

  Header set Access-Control-Allow-Methods "GET, POST"

  Header set Access-Control-Allow-Credentials "true"

  Header set Access-Control-Allow-Headers "Accept-Encoding"

</VirtualHost>

No matter what server you are using, I think the whole point is finding out the ways to config the server to redirect 404 to your index.html.

If you want to use PathLocationStrategy :

  • Wildfly configuration :
    • Create undertow-handlers.conf file to be placed in the WEB-INF
    • Content : (exclude your rest endpoints !)
      • regex['(./overview/?.?$)'] and not regex['(./endpoints.)'] -> rewrite['/index.html']
      • regex['(./deployments/?.?$)'] and not regex['(./endpoints.)'] -> rewrite['/index.html']

Single page application with Java EE/Wildfly: server-side configuration

The best solution of resolve the "router-not-working-on-reloading-the-browser" is that we should use spa-fall back. If you are using angular2 application with asp.net core then we need to defined it on "StartUp.cs" page. under MVC routs. I am attaching the code.

 app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
            routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
        });

You can try out below. It works for me!

main.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

...
export class MainComponent implements OnInit {
    constructor(private router: Router) {
        let path: string = window.location.hash;
        if (path && path.length > 0) {
            this.router.navigate([path.substr(2)]);
        }
    }

    public ngOnInit() { }
}

You can further enhance path.substr(2) to split into router parameters. I'm using angular 2.4.9

upvote
  flag
This was really helpful for handling browser refreshes! For angular 5, I had to modify it a bit to use window.location.pathname, and compare that value to expected paths. – user2748659
you can use this solution for mean application

i used ejs as view engine

 // view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

&&

app.use(function (req, res, next) {
    return res.render('index.html');
});

and also set in angular- cli .json
"apps": [
    {
      "root": "src",
      "outDir": "views",

it will work fine instead of 

 app.get('*', function (req, res, next) {
    res.sendFile('dist/index.html', { root: __dirname });
 });

its creating issue with get db calls and returning index.html
1 upvote
  flag
This worked perfectly in October 2017 for MEAN stack application. – Mindsect Team

2017-July-11: Since this is linked from a question having this problem but using Angular 2 with Electron, I'll add my solution here.

All I had to do was remove <base href="./"> from my index.html and Electron started reloading the page again successfully.

The answer is quite tricky. If you use a plain old Apache Server (or IIS), you get the problem because the Angular pages do not exist for real. They are "computed" from the Angular route.

There are several ways to fix the issue. One is to use the HashLocationStrategy offered by Angular. But a sharp sign is added in the URL. This is mainly for compatibility with Angular 1 (I assume). The fact is the part after the sharp is not part of the URL (then the server resolves the part before the "#" sign). That can be perfect.

Here an enhanced method (based on the 404 trick). I assume you have a "distributed" version of your angular application (ng build --prod if you use Angular-CLI) and you access the pages directly with your server and PHP is enabled.

If your website is based on pages (Wordpress for example) and you have only one folder dedicated to Angular (named "dist" in my example), you can do something weird but, at the end, simple. I assume you have stored your Angular pages in "/dist" (with the according <BASE HREF="/dist/">). Now use a 404 redirection and the help of PHP.

In your Apache configuration (or in the .htaccess file of your angular application directory), you must add ErrorDocument 404 /404.php

The 404.php will start with the following code:

<?php
$angular='/dist/';
if( substr($_SERVER['REQUEST_URI'], 0, strlen($angular)) == $angular ){
    $index = $_SERVER['DOCUMENT_ROOT'] . $angular . "index.html";
    http_response_code(200);
    include $index;
    die;
}

// NOT ANGULAR...
echo "<h1>Not found.</h1>"

where $angular is the value stored in the HREF of your angular index.html.

The principle is quite simple, if Apache does not find the page, a 404 redirection is made to the PHP script. We just check if the page is inside the angular application directory. If it is the case, we just load the index.html directly (without redirecting): this is necessary to keep the URL unchanged. We also change the HTTP code from 404 to 200 (just better for crawlers).

What if the page does not exist in the angular application? Well, we use the "catch all" of the angular router (see Angular router documentation).

This method works with an embedded Angular application inside a basic website (I think it will be the case in future).

NOTES:

  • Trying to do the same with the mod_redirect (by rewriting the URLs) is not at all a good solution because files (like assets) have to be really loaded then it is much more risky than just using the "not found" solution.
  • Just redirecting using ErrorDocument 404 /dist/index.html works but Apache is still responding with a 404 error code (which is bad for crawlers).

This is not a permanent Fix for the problem but more like a workaround or hack

I had this very same issue when deploying my Angular App to gh-pages. First i was greeted with 404 messages when Refreshing my pages on gh-pages.

Then as what @gunter pointed out i started using HashLocationStrategy which was provided with Angular 2 .

But that came with it's own set of problems the # in the url it was really bad made the url look wierd like this https://rahulrsingh09.github.io/AngularConcepts/#/faq.

I started researching out about this problem and came across a blog. I tried giving it a shot and it worked .

Here is what i did as mentioned in that blog.

You’ll need to start by adding a 404.html file to your gh-pages repo that contains an empty HTML document inside it – but your document must total more than 512 bytes (explained below). Next put the following markup in your 404.html page’s head element:

<script>
  sessionStorage.redirect = location.href;
</script>
<meta http-equiv="refresh" content="0;URL='/REPO_NAME_HERE'"></meta>

This code sets the attempted entrance URL to a variable on the standard sessionStorage object and immediately redirects to your project’s index.html page using a meta refresh tag. If you’re doing a Github Organization site, don’t put a repo name in the content attribute replacer text, just do this: content="0;URL='/'"

In order to capture and restore the URL the user initially navigated to, you’ll need to add the following script tag to the head of your index.html page before any other JavaScript acts on the page’s current state:

<script>
  (function(){
    var redirect = sessionStorage.redirect;
    delete sessionStorage.redirect;
    if (redirect && redirect != location.href) {
      history.replaceState(null, null, redirect);
    }
  })();
</script>

This bit of JavaScript retrieves the URL we cached in sessionStorage over on the 404.html page and replaces the current history entry with it.

Reference backalleycoder Thanks to @Daniel for this workaround.

Now the above URL changes to https://rahulrsingh09.github.io/AngularConcepts/faq

Angular apps are perfect candidates for serving with a simple static HTML server. You don't need a server-side engine to dynamically compose application pages because Angular does that on the client-side.

If the app uses the Angular router, you must configure the server to return the application's host page (index.html) when asked for a file that it does not have.

A routed application should support "deep links". A deep link is a URL that specifies a path to a component inside the app. For example, http://www.example.com/heroes/42 is a deep link to the hero detail page that displays the hero with id: 42.

There is no issue when the user navigates to that URL from within a running client. The Angular router interprets the URL and routes to that page and hero.

But clicking a link in an email, entering it in the browser address bar, or merely refreshing the browser while on the hero detail page — all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router.

A static server routinely returns index.html when it receives a request for http://www.example.com/. But it rejects http://www.example.com/heroes/42 and returns a 404 - Not Found error unless it is configured to return index.html instead

If this issue occurred in production, follow below steps

1) Add a Web.Config file in the src folder of your angular application. Place below code in it.

<configuration>
<system.webServer>
<rewrite>
    <rules>
    <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/" />
    </rule>
    </rules>
</rewrite>
</system.webServer>
</configuration>

2) Add a reference to it in angular-cli.json. In angular-cli.json put Web.config in assets block as shown below.

"assets": [
    "assets",
    "favicon.ico",
    "Web.config"
  ],

3) Now you can build the solution for production using

ng build --prod

This will create a dist folder. The files inside dist folder are ready for deployment by any mode.

Not the answer you're looking for? Browse other questions tagged or ask your own question.