Angular-cli: 404 when manually changing URL in browser to defined router route

Created on 28 Feb 2017  ·  86Comments  ·  Source: angular/angular-cli

OS?

Windows 10

Versions

[email protected]

Background

Angular App was created using angular-cli. Angular App contains a NavbarComponent that displays two menu items "Home" and "About". Angular App uses the Angular Router and a NavbarComponent to allow the user to navigate to two component views: HomeComponent View and AboutComponent View. The base route for the app is set inside index.html as . A Router Configuration File is defined and defines two routes, one route as the HomeComponent default route with a path: '' and one route as the AboutComponent Path with a path: 'about'. The ConfiguredRouterModule is exported from app.routing.ts The ConfiguredRouterModule is imported into app.module.ts. A directive is defined inside the AppComponent HTML Template. A routerLink directive is defined for each menu item link inside the NavbarComponent. To build the project I use the angular-cli command "ng build --prod". I copy files from "dist" folder to destination web server folder. Note that the destination web server folder is a sub folder under the root folder on the web server. Example "root/projects/router" and not just the "root" folder

NavbarComponent Menu Item Links correctly render Component Views

When a user clicks on either or the NavbarComponent menu item links "Home" or "About" the correct Component View displays inside the inside the AppComponent HTML Template

Issue

When a user manually changes the URL in the browser
from "http://www.abc.com/projects/router/" to "http://www.abc.com/projects/router/about" instead of the AboutComponent displaying, a 404 Page Not Found Error is displayed. Note that this behavior does not produce a 404 Page Not Found Error when running the ng serve command in the development environment. This behavior only produces a 404 Page Not Found Error when building and deploying code to a web server.

After I execute the command ng build --prod I have to change the <base href="value"> from <base href="/"> to <base href="/projects/router/">.

Note that if I try to build the project using the angular-cli command ng build --prod --base-href projects/router, after executing command if I open the index.html file inside the "dist" folder I see that angular-cli changed the <base href="value"> from <base href="/" to <base href="C:/Program Files/Git/projects/router/>

My Questions

How do I build the Angular Project so that the <base href="value"> is set correctly? More importantly why is the Angular App giving a 404 Error if a user manually changes the URL in the browser to a valid router route path? Example http://www.abc.com/projects/router/about"

Most helpful comment

@prince-sat

add this to your .htacccess

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

All 86 comments

You likely need to configure your server to rewrite unmatched URLs to your index.html.

Thank you for your response. Unfortunately your suggestion is probably not related to my question.

The key to my question is that the route that is being navigated to in the browser URL is a valid defined route. My question is really why would a user get a 404 Error if the user manually changes the URL to a valid defined route?

If I test this behavior in the Development Environment by running the ng serve command I cannot recreate this behavior when running on http://localhost:4200. Only after I try to build and deploy the code using ng build --prod am I able to recreate the 404 Error by manually changing the URL to a valid defined route. Example: http://www.abc.com/projects/router/about

I can only guess that this issue has to do with using the ng build command and setting the <base href="/"> during the build process.

Even after manually changing the index.html (after the ng build --prod) from <base href="/"> to <base href="/projects/router/> the 404 behavior still happens when a user manually changes the URL to a defined route.

@mattdistefano is right. the cli's dev server does this automatically. Angular's router uses the history api by default. when you use routerLink to change the route state it works fine because it is updating via this api. BUT if you build and use a simple server. the path /foo/bar doesn't exist on the server. so you need the server to always serve index.html so angular can resolve the route

Thank you for the info on the differences between the Angular CLI DEV Server Environment and the PROD Server Environment files that are generated by Angular CLI when using ng build --prod.

This is very confusing. I still do not understand what I need to do to build and deploy my code to Production and have my Angular Router behave the same in Production as it does in Development.

Help me understand why anyone would use the Angular CLI ng build command if the Angular Router Behavior is different between the DEV Server Environment and the PROD Server Environment.

I would think that a developer should be able to run their code using the Angular CLI ng serve command and then test their code using the Angular CLI DEV Server Environment and expect the same behavior when the developer builds and deploys the same code to their PROD Server Environment.

How do I configure my Angular Router to behave the same in my PROD Environment as it does when running in the DEV Environment?

@brookhutchinson If you want to use the history API routing, it's not angular that needs to be configured, it's your HTTP server.

If you can't change the server, you might try using the hash URL mode - see https://angular.io/docs/ts/latest/guide/router.html#!#browser-url-styles

How do I configure my HTTP server to use the History API for Angular Routing? I do not want to use a URL hash strategy. My understanding is the the URL hash strategy is an "old school" approach to routing.

Here is an example using express. Try looking at the accepted answer here. http://stackoverflow.com/questions/17456729/how-to-redirect-to-single-page-web-app-in-express-for-node.

Maybe I am not building and deploying my Angular App correctly using Angular CLI?

All I am doing is...
1) Execute ng build --prod command
2) Change file dist/index.html <base href=value>
from <base href="/"> to <base href="/projects/router">
3) Copy all the files from my Angular Project "dist" folder to my PROD Web Server Destination Folder

You may need (at least, want) to use the -bh option to ng build rather than changing the href in the built output.

You need to edit the config of your webserver to serve all static content hits directly and send all 404s to the path "/" otherwise the request will not hit your angular application on any other request than "/" directly.

The reason the app works when you navigate to "/" then use the app normally is due to the fact that angular simply pushes state into the history API without reloading the actual site in your browser. But once you refresh you'll send a request with an URI to your webserver that does not exist and your webserver will respond with a 404.

Heya @brookhutchinson, the best advice I can give you is to check out https://angular.io/docs/ts/latest/guide/deployment.html. It explains why your production server needs to be configured and offers a fair number of example configurations for common servers.

@filipesilva Thank you for the link that you provided to documentation surrounding the deployment of an Angular Project https://angular.io/docs/ts/latest/guide/deployment.html

I could be wrong, but the link that you provided addresses deployment of Angular Projects that are created with the Angular Quickstart. I am interested in learning how to properly use the Angular CLI to deploy an Angular Project that was created using the Angular CLI.

Can you please provide documentation for how to use the Angular CLI to deploy an Angular Project that was created using the Angular CLI and incorporates the Angular Router?

@brookhutchinson it doesn't matter if the project is created with the cli or not. The results of both the cli and the quickstart example is static javascript.

Just a short tip for those still bumping into this - a solution is to set the base href of your app for production deployment. Do this with ng build:

ng build --prod -bh /app/

... if your app files are in the app folder directly above index.html, e.g.

/root
    index.html
    /app
        ... app files ...

Hello I have the same problem and I don't Know how to fix this ! I tried all the above propositions but in vain :( could anyone have the perfect solution for this issue !

I also have this problem!

I also have this problem

I solved this problem by uploading a .htaccess file to my hosting provider. I found it was not recognised when I included it as part of the dist -
I think the build doesn't think it's important so gets rid of it - so I had to upload separately. The .htaccess code I just got from SO - you might have to play around with what works for your setup

@DavTho1983 you should be able to add .htaccess to your assets array in angular-cli.json similar to the favicon.

Ah! I will try that :)

@brookhutchinson @XemaA . i was able to fix the issue on my web hosting server. The issue is angular is a spa application and all routing are handle on the browser.so when you try to hit a route manually, your server tries to find the given html file on your server which does not exist therefore showing a 404 Not Found error.The work around i did is that when the route is manually hit and my server is about to throw a 404 not found error. I quickly redirect to the index.html file of my angular app which then renders the required route and view. so simply go change the 404 error of your server to redirect to your angular index.html file. see the sample link and behavior
http://taskub.com/tasker-info

@uviekelvin, Still i have same issues, Can you suggest me how to configure on IIS?

Hello everybody
@brookhutchinson did you get a solution for this problem ?
Can you help me !
Thanks

@prince-sat

add this to your .htacccess

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

@salih0313 Did you figure it out how to fix this on IIS?

To quick fix this issue you can add useHash property in your RouterModule (app module file).
i.e.
@NgModule(
{
imports:[RouterModule.forRoot(appRoutes,{useHash:true})]
})

@rbasniak I didn't fix on IIS. Simply using useHash property which mentioned above.

Thanks @xkLander
This was working fine for me.

Did anyone successfully fix this on IIS?

I am using an Angular Route as a Callback URL from a Payment Gateway but I keep getting a 404 on hitting my route in IIS.

@kolexinfos go to you website on IIS, Error Pages, then select the 404 code and set it like the image below:

image

Click ok and it should look like this:

image

Now it should work.

Nothing worked for me on IIS, for now I had to follow Angular deployment guide which suggested to add rewrite rule to web.config:

<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>

Exactly what I did to resolve my issue.

For me this redirect in .htaccess solved the problem

RewriteEngine On
ErrorDocument 404 /index.html

I faced the same issue apply, all possible solution but finally, this solve my problem

export class AppRoutingModule {
constructor(private router: Router) {
    this.router.errorHandler = (error: any) => {
        this.router.navigate(['404']); // or redirect to default route
    }
  }
}

Hope this will help you to resolve 404 error

Please see the following article
https://stackoverflow.com/questions/38054707/angular-2-azure-deploy-refresh-error-the-resource-you-are-looking-for-has-been

For Azure, I created the web.config file and added to my /src folder, also added an entry for web.config in assets array inside angular-cli.json and it fixed my problem :)

Please help me out i canot understand what i have to do to solve this issue, i dont want to add useHash as true, please help me out

useHash is a different thing - I don't think it's necessary in Angular 5. Your problem isn't routing within Angular, it's your deployment to your hosting provider. This issue is solved on this thread.

@DavTho1983 i am using angular cli 1.0.0 version is there a way to solve this issue in this version only

You should probably update to at least 1.5 I believe - with cli 1.0 I think there are still issues around routing, but there are so many SO questions around this and the issue shouldn't be with your routing within Angular if it works for you in the ng serve environment. The issue is with how it's being deployed by the server by your host - that's the part you need to understand better

Hi All,

I have deployed my angular app in IIS and by configured the rewrite rule in web.config I am able to fall in the home page of application(Which is default route). But for other pages, the routing is not working. Clicking on links in home page suppose to follow the routing rule and should navigate to the respective components. Instead of that, it is redirecting to the same home page url. Does anyone here face similar issue? If so, could you please help to resolve the same..?

Thanks in advance. :)

Read the thread, do the figuring out. Every week someone on here asks practically the same question. Just read it mate.

@DavTho1983 , I have fixed it by my own. Thanks :)

Jithesh - I'm facing the same issue. Could you share your solution? Really appreciate your help.

Jithesh - I have fixed the issue using following link..
https://groups.google.com/forum/#!topic/angular/JqhmL6ocPDY

Thanks you..

DON'T USE REWRITE IN WEB.CONFIG as this will will redirect to a point and again it will try to execute some piece of code that actually not required. This will hamper the IIS i have tested by checking the event logs in the server. use useHash location strategy instead.

If Apache is web server then make .htaccess file and paste the below:

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /sub-folder-name/index.html

After All this, if you haven't tried lite-server please try it first !!

@uviekelvin
I managed to use a rewrite rule to send the index.html file but once the page reaches the client, how does the app "knows" what was the route that was requested originally?
At first, I thought you were sending some special header for that but I don't see one.
can you explain that part, please?

@brookhutchinson , I had the same problem

  1. run ng build --prod
  2. dist folder will be created, paste the following .htaccess file inside
  3. upload to your server (in my case shared hosting)

Add .htaccess in your root folder, same level with your index.html with this HTACCESS content

RewriteEngine On  
  # If an existing asset or directory is requested go to it as it is
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
  RewriteRule ^ - [L]

  # If the requested resource doesn't exist, use index.html
  RewriteRule ^ /index.html

screen shot 2018-02-19 at 1 20 43 am
I've deployed my angular 5 project on aws s3 bucket and i am getting this '403 Forbidden error' if I referesh the page on a routed component(awsbucketurl/books), I don't wanna use HashLocationStrategy, please help me out here.

Use this with HTTPS Websites

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

For HTTP Websites

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html


I'm having the same problem but only with lazy loading modules. When I hit a route that is not part of a lazy loading module it loads, but when I try for lazy loading modules Apache throws a 404 error.

In my local environment, it works great for all routes.

All this is happening to me after upgrading to Angular 5 and ng cli 1.6.8.

I wanted to show the 404.html for the wrong URLs.
So,
{ path: '**', component: PageNotFoundComponent }
I have tried with above thing abut it was not working properly.

Then I have used below code, and it's working fine.
Woeking code 👍

PageNotFoundComponent Route:

{ path: '404', component: PageNotFoundComponent }

export class AppRoutingModule {
constructor(private router: Router) {
    this.router.errorHandler = (error: any) => {
        let routerError = error.toString();
            if (routerError.indexOf('Cannot match any routes') >= 0 ) {
                this.router.navigate(['/404']);
            } else {
                throw error;
            }
    }
  }
}

Thanks to @mejayantpatil

I ended up using lite-server. It automatically serves /index.html on any 'unknown' route. I hope I can save you guys some time of searching, because, jekyll (GitHub), apache (local Windows), http-server have been beasts to me while solving this problem.

For those who use the Firebase Hosting as web server to host a Angular application. You should check this link firebase hosting redirect.

As mentioned you have to add those lines of code in your firebase.json

"hosting": {
  // Add the "rewrites" section within "hosting"
  "rewrites": [ {
    "source": "**",
    "destination": "/index.html"
  } ]
}

It just save my day, so I share.

@all
ng build --base-href="/TEST/"

ng server --base-href="/NIHB/"

This will help to solve this error

If you are deploying your angular app on JBOSS/Apache as war file, then add following in your web.xml file:-

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

This will redirect to index.html of your angular app in case of 404 not found error which then renders the required route and view. (It works even if you are manually trying to go to a correct route.)

Does anyone know how to use the useHash solution with Angular 6 while using a appRoutingModule file for their routes?

use inside into tag.
Note it should be top inside head tag.



other css and jquery ...

How this can be fixed on NGNIX based server ?

@alwinaugustin

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

None of the above .htaccess configs worked for me. Why this is closed?

@kamlekar It's closed because it's not an issue with angular-cli. The issue is webserver configuration related. If none of the comments above helped you then try stackoverflow instead to get additional help.

For me none of the above .htaccess issues worked. Our admin did the following change in httpd.conf file, (in two servers) which worked:

<Directory "/var/www/html/">
    Options FollowSymLinks
    Allow from all
    AllowOverride All
</Directory>

For Apache Server

  • Create a file name .htaccess
  • Edit that file and write index.html instead of index.php
  • For those who dont have any code, can write the code below in your .htaccess file :
RewriteEngine On
      # If an existing asset or directory is requested go to it as it is
      RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
      RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
      RewriteRule ^ - [L]
      # If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

Do any one have way to fix aws s3 deployment issue highlighted by "gaurav-pantelwar commented on Feb 18 • " ?

Yes @pankajojha , just make htaccess file in your main directory if you are on apache server. See above answer from @smitpatelx

Do any one have way to fix aws s3 deployment issue highlighted by "gaurav-pantelwar commented on Feb 18 • " ?

In S3 bucket's Properties > Static web hosting try to set Error document to index.html that way non existing objects/path will be redirected to index.html

I'm testing app using ZEIT now solution... I cannot use .htaccess not IIS solutions above.

Using hash seems great

@NgModule({
  imports: [RouterModule.forRoot(routes, {useHash: true})],
  exports: [RouterModule]
})
export class AppRoutingModule { }

But I am considering lite-server as another one sugested.

Hello, i've checked the above comment carefully.
Here's a problem facing now.
Angular 6 production deployment into google app engine.
-- app.yaml --
runtime: python27
api_version: 1
threadsafe: true
handlers:

  • url: /
    static_files: dist/index.html
    upload: dist/index.html
  • url: /
    static_dir: dist
    ~
    it works properly with entering myapp.appspot.com
    but it doesn't work with 404 not found when i refresh the browser.
    It would be helpful if you advice something.

Concerning this i used .htacees file to solve all issue
RewriteEngine On

If an existing asset or directory is requested go to it as it is

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

If the requested resource doesn't exist, use index.html

RewriteRule ^ /index.html

For anyone still having trouble with this. I would try using angular-cli-ghpages, which will deploy your Angular app straight to Github pages with no problems. You should be able to manually go to a given route or refresh a page with no 404's.

Hello Geeks,
I had the same problem while Deploying angular build on IIS server, I handled this issue by adding the web.config file at the root directory of the site, with below content:

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> </system.web> <system.webServer> <rewrite> <rules> <rule name="Rewrite Rule" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" /> </conditions> <action type="Rewrite" url="/" /> </rule> </rules> </rewrite> </system.webServer> </configuration>

Use this with HTTPS Websites

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

For HTTP Websites

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

Works great. I have <base href="/"> also

You likely need to configure your server to rewrite unmatched URLs to your index.html.

It worked for me with this in web.php routes file, of course in my index i have the same code from index generated in ng run build

Route::fallback(function () {
return view('index');
});

@sushinpv code is working for me. if i hit an url in browser it reloading the index.html rather than 404 error page in HTTP server.
But I have two modules in my application one is user and another one is admin module.. when i hit my_app url it will work for user module.. if i hit
my_app/admin it should render the admin page.. Now its not working, if i hit any of the url it's redirecting to index.html... its working in localhost:4200

Is there any solution for this? i'm working with Angular 7
thanks

@Lavanya2021 Hi, Which backend server you are using ?

NGINX or APACHE ??

Both required two different configuration !

  • Can you please elaborate on this point my_app/admin it should render the admin page.. Now its not working,. Like when you hit my_app/admin what output you are getting!, So that i would be able to help you out!

For reference you can checkout these pages https://lms.thegateacademy.com/ and https://lms.thegateacademy.com/dashboard/course

@sushinpv Hii,
I'm using APACHE server. As i said earlier,, i have 2 modules in my application, now i should make 2 urls to access the each module from the same application one for users and another one for admin. 1st is like baseurl as defined in the index.html i.e., for example localhost:4200 or href="/" in index.html for user module and also want to access another one is for admin module like localhost:4200/admin from the same application.. i'm not getting how to access the 2nd url.

Please help me out..

Please tell me if manually changing the URL is equivalent to clicking the refresh button. For example if a user is on a page deep inside an Angular app and wishes to reload the data there, they're likely to click the browser refresh button. Configuring the backend to redirect the browser to the app's entry page is cool but then what happens - does the router wake up in the user's browser, or does the user have to click-click-re-navigate to the old page? Thx.

The server configuration should not be sending a redirect (30x) to the client but rather rewriting to send the content of index at the requested URL.

Hello Geeks,
I had the same problem while Deploying angular build on IIS server, I handled this issue by adding the web.config file at the root directory of the site, with below content:

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> </system.web> <system.webServer> <rewrite> <rules> <rule name="Rewrite Rule" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" /> </conditions> <action type="Rewrite" url="/" /> </rule> </rules> </rewrite> </system.webServer> </configuration>

very very thank you man
very helpful this solution

Hi. thanks for your solutions. but they didn't work for me. now I have this error : An Unexpected token .... >

How this can be fixed on AWS S3 based server ? please help with this question..

Heya @brookhutchinson, the best advice I can give you is to check out https://angular.io/docs/ts/latest/guide/deployment.html. It explains why your production server needs to be configured and offers a fair number of example configurations for common servers.

As per the link, it says to add-in web.config file, but normally dist folder doesn't have web.config.
Even I add manually web.config in dist, it doesn't work.

What exactly should be done here to be working in IIS?

@filipesilva @brookhutchinson

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

donaldallen picture donaldallen  ·  3Comments

gotschmarcel picture gotschmarcel  ·  3Comments

NCC1701M picture NCC1701M  ·  3Comments

rajjejosefsson picture rajjejosefsson  ·  3Comments

JanStureNielsen picture JanStureNielsen  ·  3Comments