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

OS?

Windows 10

Versions

angular-cli@1.0.0-rc.0

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 <base href="/">. 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 <router-outlet> 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 <router-outlet> 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"

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 29
  • Comments: 86 (9 by maintainers)

Commits related to this issue

Most upvoted comments

@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

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})] })

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.

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

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?

I also have this problem

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.

I also have this problem!

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 !

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.

@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

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>

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

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

@all ng build --base-href=“/TEST/”

ng server --base-href=“/NIHB/”

This will help to solve this error

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.

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

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

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

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


@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

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

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

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.

@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

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

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

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

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>

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.

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

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

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

@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