66

I am going to develop a simple Angular 2 application. I have created a project with routing, using Angular CLI and added several components to the app using 'ng generate component ' command. Then I specified routing in the app-routing.module.ts as following.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { UserComponent } from './user/user.component';
import { ErrorComponent } from './error/error.component';
import { SpecialpageComponent } from './specialpage/specialpage.component';
const routes: Routes = [
 {
 path: '',
 component: HomeComponent
 },
 {
 path: 'about',
 component: AboutComponent
 },
 {
 path: 'user',
 component: UserComponent
 },
 {
 path: 'specialpage',
 component: SpecialpageComponent
 },
 {
 path: '**',
 component: ErrorComponent
 }
];
@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule],
 providers: []
})
export class AppRoutingModule { }

app.module.ts is as following.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ErrorComponent } from './error/error.component';
import { UserComponent } from './user/user.component';
import { SpecialpageComponent } from './specialpage/specialpage.component';
@NgModule({
 declarations: [
 AppComponent,
 HomeComponent,
 AboutComponent,
 ErrorComponent,
 UserComponent,
 SpecialpageComponent
 ],
 imports: [
 BrowserModule,
 FormsModule,
 HttpModule,
 AppRoutingModule
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

I have not added any modifications for the other components. Then I deployed the application using 'ng serve' command and the app works fine with the links. Eg: http://localhost:4200/about

enter image description here

But when I deploy the project in http-server, the links do not work as expected. I deployed the app using 'http-server ./dist' command and the app gets deployed fine, but the links do not work. When I go to 'http://localhost:4200/about', it gives 404 error.

enter image description here

Am I doing anything wrong? Why 'ng-serve' works and 'http-server' does not work?

Any help would be appreciated. Thanks in advance.

I have uploaded my project to github.

asked Apr 21, 2017 at 6:03
13
  • 6
    Try imports: [RouterModule.forRoot(routes, {useHash: true})],. If it works this way, you need to enable HTML5 pushState on your production server. Commented Apr 21, 2017 at 6:11
  • @GünterZöchbauer, I tried, but no luck Commented Apr 21, 2017 at 7:03
  • 1
    Yes, do not use useHash:true :D. As I said in my initial comment. You have to configure the server to support HTML5 pushState. useHash:true was only to debug the cause of the issue. Commented Apr 21, 2017 at 8:08
  • 1
    @GünterZöchbauer, thank you for your invaluable information regarding this matter. I will try to find a solution for this. Thanks again Commented Apr 21, 2017 at 11:30
  • 2
    Did you find out the solution. i have same issue. Commented Feb 13, 2018 at 17:08

19 Answers 19

54

This problem is solved by implementing HashLocationStrategy which adds # to all your routes. You achieve this by adding HashLocationStrategy to AppModule providers.

providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],

and add the corresponding import

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

This will solve your problem.

And if you don't want to use the HashLocationStrategy, you can use the PathLocationStrategy, and so your Angular app will not show Hash in the URL.

Phil Dukhov
90.9k22 gold badges274 silver badges301 bronze badges
answered Jun 19, 2017 at 13:11
Sign up to request clarification or add additional context in comments.

7 Comments

I have same issue and I also have this in my app.modules.ts. I am not getting any 404 error. After app component init method nothing is loading as if my routes are not working. ng serve works fine but my localhost not..
Thank you! helped me. But is it ok to always show a hashtag in the deployed websites urls? Hmm
@ninjaxlite I Updated my answer if you don't want to show Hashtag in URLs
I feel like this shouldn't have to be a thing. Fix this Google. Change the construct of the entire internet to appease me.
This. I've tried all kinds of things to get it to run both on my nginx and IIS - to no avail. Until I came across this one. Wouldn't we all want angular to use the HashLocationStrategy by default? Or, even farther, it shouldn't even be an option NOT to use it?
|
24

This is because http-server does not support fallback like lite-server or web pack-dev server. This is why it shows 404 not found. There are two solution to resolve this issue:

  1. you can use HashLocationStrategy like mentioned above.
  2. If you are deploying it to Apache or IIS server then you can simply add configurations as mentioned here!

Note: For development you can use lite-server.

Hope this will help you.

Davide
2,1242 gold badges26 silver badges43 bronze badges
answered Oct 4, 2017 at 13:17

Comments

15

I've resolved this problem with adding this in AppModule Providers:

providers: [{provide: LocationStrategy, useClass: PathLocationStrategy}]

and importing

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

Then I created .htaccess:

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

Everything works great without # in URLs :)

answered Jul 25, 2018 at 6:12

3 Comments

Where i have to add .htaccess file?
@jaykhatri In main directory (there where Angular app is) on your web server. It's probably public_html.
Created the .htaaccess file with contents from your post. Uploaded to the root of the website. it works!. Thanks i didnt add the PathLocationStrategy . i am using angular 13.3.3
10

It will be solved in this way:

Case-1: For version less than Angular 5.1

1) Use HashLocationStrategy like mentioned below: In AppModule do the following.

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

1.2) providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]

Case-2: For version equal or more than Angular 5.1

2.1) Angular has introduced this property onSameUrlNavigation for overcoming refresh issue on the server.

2.2) Add onSameUrlNavigation to the RouterModule.forRoot in imports array .

a) In Application main routing module, i,e app.routing.module.ts / app.routing.ts add the property

See below:

@ngModule({
 imports: 
 [
 RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})
 ],
 exports: [RouterModule],
 });

Hope it help somebody.

Benjamin
8,2483 gold badges37 silver badges48 bronze badges
answered Mar 14, 2018 at 11:54

Comments

6

It will happen because it goes to find a page about which is not there inside at all hence 404. Possible options:

  1. If you want to go with http-server then use a proxy which will redirect everything to http://localhost:your-port.

    Option: -P or --proxy Proxies all requests which can't be resolved locally to the given url. e.g.: -P http://someurl.com

  2. Don't use express at all. Create your own http-server using express & Redirect everything to index.html

    Assuming public is your folder where u keep all transpiled things.

    var express = require('express');
    var app = express();
    var path = __dirname + '/public';
    var port = 8080;
    app.use(express.static(path));
    app.get('*', function(req, res) {
     res.sendFile(path + '/index.html');
    });
    app.listen(port);
    
TT.
16.2k6 gold badges53 silver badges95 bronze badges
answered Apr 21, 2017 at 6:10

2 Comments

I'm sorry I did not get you quite well. I'm really a newbie to Angular. I'm not doing anything complex here. An regarding your first option, I tried to host my server and I accessed the URL without a port. Only the root URL works. Cannot navigate into other links.
http-server --port 4200 -P http://someurl.com raise an infinite loop in my case
5

If you, like me, want to make no code changes at all, simply use this instead:

https://www.npmjs.com/package/angular-http-server

answered Dec 10, 2018 at 14:32

Comments

3

For Apache server:

in the Production servers

Add or create ".htaccess" file into the project root, add a rewrite rule to the .htaccess file as shown

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
answered Feb 13, 2018 at 4:39

Comments

2

I also faced this issue and found a solution that does not require HashLocationStrategy solution.

Issue is, a server like tomcat looks for a actual folder (for eg : /about ) which does not exist in angular app, as its a single page application. So every request needs to be redirected to index.html.

Easiest way to fix this issue is to add the following java class and override addResourceHandlers() method like below:

@Configuration
class WebMVCCustomConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
 registry.addResourceHandler("/**").addResourceLocations("classpath:static").resourceChain(true)
 .addResolver(new PathResourceResolver() {
 @Override
 protected Resource getResource(String resourcePath, Resource location) {
 String path = "static/";
 path += (resourcePath.contains(".") && !resourcePath.equals("index.html")) ? resourcePath : "index.html";
 Resource resource = new ClassPathResource(path);
 return resource.exists() ? resource : null;
 }
 });
 }
 }

This will fix all the issues and this solution does not exist anywhere.

answered Dec 31, 2019 at 6:33

1 Comment

Good to know that there is solution like this, but I think is better to you use mechanisms provided by angular like that one which is mentioned above -> HashLocationStrategy. Cheers :)
2

As per the documentation at https://angular.io/guide/deployment (Apache, you could also look for nginx) You need to point the server to index.html using the .htaccess file as

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
dbc
120k27 gold badges272 silver badges403 bronze badges
answered Oct 22, 2018 at 2:15

Comments

1

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

  • This code might not work for SSL certificate - contact your hosting provider OR visit https://httpd.apache.org/docs/current/howto/htaccess.html to refer to docs.

answered Oct 3, 2018 at 8:58

Comments

1

You should try specifying the url in the build from the point the app should initialize:

Ng build --prod --base-href="http://your.url.com/subdirectory/etc"
Nick
147k23 gold badges67 silver badges106 bronze badges
answered Jan 14, 2019 at 2:25

Comments

1

The exact reason why this particular issue is being faced is because of your server settings.

So when you implement the application there are certain steps that you will have to take. One of the essential steps is to mark a particular segment of your path say: http://domain-name/main where main being the path segment must be used as the identifier in your server settings say your server.js or app.js when it comes to a node backend or a webconfig file for IIS and Tomcat deployment.

The reason for marking a particular segment is so that when the server receives any request with that particular segment + additional you reroute it to your application in www or public folder for the angular router to kick in.

This process is known as url rewriting. Hence if the web server or the app server depending on the application size is not under your control then please use hashLocationStratergy else it is always neat to use pathLocationStartergy as it is helpful when it comes to history tracking and other aesthetic and performance benefits.

To read more on this you can visit these links:

For IIS: https://blog.angularindepth.com/deploy-an-angular-application-to-iis-60a0897742e7

answered Apr 16, 2019 at 9:53

Comments

0

Add a dot in your base href strings.

Correct

<base href="./home">

Wrong

<base href="/home">

http://www.wisdomofjim.com/blog/solved-problems-with-resource-loading-failures-when-deploying-angular-2-webapps-live

answered Jun 12, 2019 at 11:23

Comments

0

If you use href, change them to routerlink.

answered Dec 21, 2021 at 15:45

Comments

-1
export const routes: Routes =[
 **{ path: '', redirectTo: '/', pathMatch: 'full'},**
 { path: 'about', component: AboutComponent},
 { path: 'user', component: UserComponent},
 { path: 'specialpage', component: SpecialpageComponent},
 { path: '**', component: ErrorComponent}
 ];

Look at the content of blockquote. And then you give the name of "HttpModule" at providers:[] in app.module.ts

Thanks.

answered Apr 21, 2017 at 7:15

1 Comment

@C.Peterscu I did as you have mentioned. But I couldn't get it work. I uploaded my project to github.com/kinathru/multiple-page-app.
-1

You can do it while registering your RouterModule.forRoot, you can pass a second object with propert {useHash: true} like the below :

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
import {appRoutes} from './app.routes';
@NgModule({
 declarations: [AppComponent],
 imports: [BrowserModule],
 RouterModule.forRoot(appRoutes , {useHash: true})],
 providers: [],
 bootstrap: [AppComponent],
})
export class AppModule {}
answered Jun 30, 2017 at 8:46

3 Comments

i have the same problem but the solution does not work
I have same problem. ng serve works good but when I deploy to my local, localhost/ doesnot work
don't forget to use the hash in your url when you test it, like: 127.0.0.1/#/home
-1

Change your index.html

<base href="/">
 to 
<base href="./">

Because we are using Tomcat we have mentioned this(.) for Routing is based on this(/) So same like http-server

I mean running normally ng serve you have seen only http://localhost:4200/

but run in server you have put your build into(dist) in webapps

so its come like

http://localhost:8080/dist/

so you need to add <base href="./">

i think this is the problem for you may be solved.

answered Oct 10, 2017 at 9:55

Comments

-1

in the project folder create .htaccess file an then write

RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]

follow this link: https://angular.io/guide/deployment

answered Jan 21, 2018 at 18:04

Comments

-1

I used lite-server.

npm i -D lite-server

then in my package.json file:

"scripts": {
 "ci:serve:employee-onboarding": "ng build --prod --project=employee-onboarding && lite-server -c lite-server-config.json"
}

to run it: npm run ci:serve:employee-onboarding

my lite-server-config.json file looks like this

{
 "port": 4201,
 "server": { "baseDir": "dist/apps/employee-onboarding" }
}
answered Nov 4, 2019 at 16:00

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.