Angular 2: 404 error occur when I refresh through the browser

For people (like me) who really want PathLocationStrategy (i.e. html5Mode) instead of HashLocationStrategy, see How to: Configure your server to work with html5Mode from a third-party wiki:

When you have html5Mode enabled, the # character will no longer be used in your URLs. The # symbol is useful because it requires no server side configuration. Without #, the URL looks much nicer, but it also requires server side rewrites.

Here I only copy three examples from the wiki, in case the Wiki get lost. Other examples can be found by searching keyword "URL rewrite" (e.g. this answer for Firebase).

Apache

<VirtualHost *:80>
    ServerName my-app

    DocumentRoot /path/to/app

    <Directory /path/to/app>
        RewriteEngine on

        # Don't rewrite files or directories
        RewriteCond %{REQUEST_FILENAME} -f [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^ - [L]

        # Rewrite everything else to index.html to allow HTML5 state links
        RewriteRule ^ index.html [L]
    </Directory>
</VirtualHost>

Documentation for rewrite module

nginx

server {
    server_name my-app;

    root /path/to/app;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Documentation for try_files

IIS

<system.webServer>
  <rewrite>
    <rules> 
      <rule name="Main Rule" 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>

In fact, it's normal that you have a 404 error when refreshing your application since the actual address within the browser is updating (and without # / hashbang approach). By default, HTML5 history is used for reusing in Angular2.

To fix the 404 error, you need to update your server to serve the index.html file for each route path you defined.

If you want to switch to the HashBang approach, you need to use this configuration:

import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {LocationStrategy, HashLocationStrategy} from '@angular/common';

import {MyApp} from './myapp';

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

In this case, when you refresh the page, it will be displayed again (but you will have a # in your address).

This link could help you as well: When I refresh my website I get a 404. This is with Angular2 and firebase.

Hope it helps you, Thierry


Update for Angular 2 final version

In app.module.ts:

  • Add imports:

      import { HashLocationStrategy, LocationStrategy } from '@angular/common';
    
  • And in NgModule provider, add:

      {provide: LocationStrategy, useClass: HashLocationStrategy}
    

Example (app.module.ts):

import { NgModule }       from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule],
    providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
    bootstrap: [AppComponent],
})
export class AppModule {}

Alternative

Use RouterModule.forRoot with the {useHash: true} argument.

Example:(from angular docs)

import { NgModule } from '@angular/core';
...

const routes: Routes = [//routes in here];

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(routes, { useHash: true })
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

I had the same problem. My Angular application is running on a Windows server.

I solved this problem by making a web.config file in the root directory.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS" 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>