237

I have stored my single-page application in my server within a folder named as "myapp". I have changed the URL in the base to http://example.com/myapp/`.

My project has two pages. So I implement Angular 2 routing. I set the default page as login. When I type http://example.com/myapp/ in my browser it will redirect automatically to http://example.com/myapp/login. But if refresh that page I get a 404 error, saying that http://example.com/myapp/login is not found.

But if I run my project using the lite server everything is working. In this case the base URL in index.html will be "/". How do fix it?

starball
  • 20,030
  • 7
  • 43
  • 238
DAN
  • 3,140
  • 5
  • 20
  • 22
  • Currently, I worked with the angular 9 application and deployed it on an IIS server with a web.config file and when we refresh the page it loads the angular app correctly. I think this is not an issue with the angular application. But when I deployed the code to the Ubuntu server application gives the 404 not found error because we did not configure the URL rewrite rules. After adding the.htaccess file for rewrite the URL's It works on refresh. – Ravindra Vairagi Oct 16 '20 at 12:30
  • I had the same problem in production, in development was fine. This answer fixed this: https://stackoverflow.com/a/39103122/12603542, with `useHash: true`, Ill have to just figure out how to get rid of `/#/` – bakunet Jun 02 '21 at 09:47

7 Answers7

294

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 { }
Community
  • 1
  • 1
Asaf Hananel
  • 7,092
  • 4
  • 24
  • 24
  • 2
    Answers may be rearranged according to popularity, so relative positioning will not be preserved. Please provide a link to the other answer in your answer. – Jonathan Mee Aug 23 '16 at 14:16
  • Does this work in IE? I run angular2 app on Apache (Windows Server) and I get 404 error page. – Timson Aug 26 '16 at 05:37
  • @Asaf Hananel , will this work for RC-6 ? – refactor Oct 13 '16 at 10:31
  • @CleanCrispCode yes, it should work, if not let me know – Asaf Hananel Oct 13 '16 at 12:07
  • 33
    This does work for me. Thank you. But is there a way to lose the #? – Sparked Oct 27 '16 at 12:55
  • 2
    Yes this works for me too. But I am using auth0 for authentication and I have to provide allowed urls. when I refresh page which adds a hash now, then login it wont accept the url. What is a suggestion to fix this or remove the hashtags when the page is refreshed? – wuno Nov 12 '16 at 13:02
  • @Sparked Any solution you have found? – Shabbir Dhangot Mar 15 '17 at 07:11
  • @ShabbirDhangot I'm afraid not. I ended up living with the #, in the end. – Sparked Mar 15 '17 at 08:39
  • @Sparked can we change # to any #name or something? – Shabbir Dhangot Mar 15 '17 at 10:26
  • 1
    Adding providers first solution of this answer(providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}], bootstrap: [AppComponent],) DID WORK!! thanks a TON! /\! – HydTechie May 19 '17 at 09:20
  • 1
    There is a way to not use the hash (#) in the link?? The solution worked fine but now i have a link like: "test/app/#/login" – PriNcee Aug 22 '17 at 09:10
  • @PriNcee Sure, there is. See [mine](https://stackoverflow.com/questions/35284988/angular-2-404-error-occur-when-i-refresh-through-browser/40833154#40833154). (Actually I prefer the one without the hash; it feels less hacky.) – Franklin Yu Sep 12 '17 at 14:16
  • Does this method works on Angular 5? because I am also getting error while refreshing page – Hidayt Rahman Apr 12 '18 at 05:45
  • Yes this works for me too. But I am using auth0 for authentication and I have to provide allowed urls. when I refresh page which adds a hash now, then login it wont accept the url. What is a suggestion to fix this or remove the hashtags when the page is refreshed? – HEMANT PATEL May 10 '18 at 09:53
  • @HRPATEL Read through all the answers below and you will find a solution. – Franklin Yu Aug 07 '18 at 18:26
  • hi Thanks for help but it raised another problem I am using this at login page now my first time login does not succeed but second time wit same credentials it succeeds???? – ThinkTank Mar 05 '19 at 15:09
  • What would be value of const routes: Routes = [//routes in here]; ? – user1459497 Apr 14 '21 at 14:57
  • I was facing the same issue but it was working fine in local but giving 404 in the PROD. Adding the above-mentioned `providers` it worked like a charm, thanks @AsafHananel – Raj Rajeshwar Singh Rathore Sep 27 '21 at 04:03
181

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>
Franklin Yu
  • 8,920
  • 6
  • 43
  • 57
  • This topic relates to Angular 2(4) - your response is AngularJS related – Playnox Sep 08 '17 at 22:35
  • 3
    @Playnox Everything mentioned here also applies to Angular 2 to 4. (Actually I didn't begin using Angular since 2.) You may have jumped to the conclusion by the link to Angular-UI wiki, where code sample is AngularJS. – Franklin Yu Sep 08 '17 at 22:53
  • 3
    And I get downvoted because of the false accusation. Well, at least there is some feedback... – Franklin Yu Sep 12 '17 at 14:13
  • @FranklinYu Have you seen any configurations for WebLogic servers? Haven't had any luck. – overboard182 Dec 28 '17 at 18:07
  • @overboard182 Sorry, I don't have any experience of WebLogic. Some online Q&A (like [this one](https://serverfault.com/questions/177795/url-rewrite-in-weblogic-11g)) suggest that WebLogic does not support URL Rewriting, so you have to do it either in front of WebLogic (reverse proxy) or behind WebLogic (let WebLogic proxy request to another application or Servlet). – Franklin Yu Dec 28 '17 at 22:55
  • Hi, sorry I encoutered this error and when I put your apache config I got those errors Uncaught SyntaxError: Unexpected token <, what I miss in my config? – Adouani Riadh Jan 03 '18 at 10:46
  • @AdouaniRiadh Is there line number for this error? – Franklin Yu Jan 03 '18 at 21:42
  • Morning; I found a solution. it's very similair as yours configuration https://stackoverflow.com/questions/48076301/apache-angular-oauth-redirection-resource-not-found?answertab=votes#tab-top Thanks – Adouani Riadh Jan 04 '18 at 09:11
  • I'm not having any luck using the IIS one for my server. When I refresh from a route it goes back to the root. – yarz-tech Mar 02 '18 at 18:41
  • 4
    This answer in my view is the correct one, it preserves the HTML5 features of angular and makes the server function correctly. – crooksey Mar 16 '18 at 09:25
  • Great It works well for nginx. For me this is also the correct answer. – Kevin Vincent Mar 28 '18 at 08:23
  • @HimanshuDhirajMishra Nginx? Did you mean Apache? – Franklin Yu May 18 '18 at 04:25
  • @FranklinYu, yes ! I did changes in .htaccesss – Himanshu Dhiraj Mishra May 18 '18 at 05:06
  • You can also use .htaccess that works for me as below Options +FollowSymLinks RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !index RewriteRule (.*) index.html [L] – Stephen Ngethe Sep 07 '21 at 23:30
  • my problem in nginx I put root /path/to/app; inside location thank you – Mohamed Farouk Dec 08 '21 at 20:26
  • didn't work for me – java-addict301 Jun 28 '22 at 19:54
155

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

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • 2
    This solved my problem, thanks a lot. However, is there any disadvantage in using the HashBang approach?, I mean in terms of SEO or anything else? – Werner Echezuria May 21 '16 at 19:10
  • 2
    What if we don't want to use HashLocationStrategy but PathLocationStrategy? – Ben Oct 11 '16 at 09:36
  • 3
    @Ben As Thierry mentioned, "if you want not having a 404 error, you need to update your server to serve the index.html file for each route path you defined." Detailed ways for each server software are in [Angular Wiki about working with `html5Mode`](https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode), or refer to the linke provided by Thierry for Firebase configuration. – Franklin Yu Nov 27 '16 at 19:16
  • 1
    answer below is for update for angular2 final version – trees_are_great Jan 29 '17 at 23:19
  • Did you find this solution in Angular 4? – Bhavesh Hirpara Aug 05 '17 at 14:48
  • @BhaveshHirpara Most answers in this version also works for Angular 4. – Franklin Yu Dec 29 '17 at 16:32
  • 3
    Franklin Yu's answer should actually be the accepted answer. Thierry Templier's answer just says put back the # to get rid of the problem, which isn't an answer or use the link provided with assumes the poster is using firebase, which the poster probably is not. The wiki provided by Franklin answers the questions, with a side note, for Apache, you can add the same config in an .htaccess file. – Dana Harris Jul 12 '18 at 01:59
  • This answer would be more complete if you included how to update the server to serve the index.html file for each route path defined (PathLocationStrategy). Thanks for what you've contributed thus far though. – Kyle Vassella Aug 16 '18 at 22:22
  • @KyleVassella This answer wants you to change from `PathLocationStrategy` to `HashLocationStrategy`. The solution of sticking to path location is explained in other answers. – Franklin Yu Aug 24 '18 at 17:15
  • 1
    Can you please provide the solution for Angular 7. I am getting 404 on page refresh in angular 7 with spring boot (REST service). both are running on different ports. – Swati Thakare Apr 24 '19 at 09:24
  • Hash technique works, But I think we can simple add .htaccess to get this fixed with the below code RewriteBase / RewriteRule ^index.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] – Vishal J Nov 15 '20 at 11:30
37

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>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bennie-be
  • 403
  • 5
  • 5
  • @DaneVinson [The Angular Wiki](https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions) is even earlier. Anyway he should probably give someone credit. – Franklin Yu Oct 27 '17 at 15:02
  • In case of WebApi service (For the Server). Notice, that the angular application not placed in the same folder of WebApi. You can create another folder, and change the href in index.html – Shneor May 26 '19 at 09:58
31

Perhaps you can do it while registering your root with RouterModule. You can pass a second object with property useHash:true like the below:

import { NgModule }       from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import { ROUTES }   from './app.routes';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule],
    RouterModule.forRoot(ROUTES ,{ useHash: true }),],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}
ngShravil.py
  • 4,742
  • 3
  • 18
  • 30
Niyaz
  • 2,677
  • 3
  • 21
  • 40
  • 4
    This is the simplest approach if you just want to get something working quickly. However, anuglar.io recommends against it "Stick with the default unless you have a compelling reason to resort to hash routes." https://angular.io/docs/ts/latest/guide/router.html – justanotherdev Oct 02 '16 at 06:39
  • 1
    just adding { useHash: true } solved my problem thanks ! – fuat Nov 05 '19 at 09:27
8

For people reading this that use Angular 2 rc4 or later, it appears LocationStrategy has been moved from router to common. You'll have to import it from there.

Also note the curly brackets around the 'provide' line.

main.ts

// Imports for loading & configuring the in-memory web api
import { XHRBackend } from '@angular/http';

// The usual bootstrapping imports
import { bootstrap }      from '@angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '@angular/http';

import { AppComponent }         from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { Location, LocationStrategy, HashLocationStrategy} from '@angular/common';

bootstrap(AppComponent, [
    APP_ROUTER_PROVIDERS,
    HTTP_PROVIDERS,
    {provide: LocationStrategy, useClass: HashLocationStrategy}
]);
KDC
  • 1,441
  • 5
  • 19
  • 36
7

If you're running Angular 2 through ASP.NET Core 1 in Visual Studio 2015, you might find this solution from Jürgen Gutsch helpful. He describes it in a blog post. It was the best solution for me. Place the C# code provided below in your Startup.cs public void Configure() just before app.UseStaticFiles();

app.Use( async ( context, next ) => {
    await next();

    if( context.Response.StatusCode == 404 && !Path.HasExtension( context.Request.Path.Value ) ) {
        context.Request.Path = "/index.html";
        await next();
    }
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
StackOverflowUser
  • 945
  • 12
  • 10