Reputation: 3587
I am using Angular 2.0.0-alpha.30 version. When redirect to a different route, then refresh the browser , its showing Cannot GET /route.
Can you help me with figuring why this error happened.
Upvotes: 205
Views: 123366
Reputation: 4441
In my case I was using Angular project template with ASP.NET Core 7. After deploying to IIS (Web App on Azure), page refreshes started returning 404 error.
In Program.cs
this is already handled with this line of code.
app.MapFallbackToFile("index.html");
But if your index.html
is inside a subfolder within wwwroot
, this is how to configure it. (This was our case, therefore above line of code didn't really do anything.)
var fileProvider = new PhysicalFileProvider(
Path.Combine(app.Environment.WebRootPath, "MySubFolder"));
app.MapFallbackToFile("index.html", new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = ""
});
This fixed our issue (full Program.cs file). If the index.html
is in a folder (e.g.: ClientApp/dist) outside wwwroot
, fileProvider
should be created like this.
var fileProvider = new PhysicalFileProvider(
Path.Combine(app.Environment.ContentRootPath, "ClientApp", "dist", "index.html"));
Do not need a web.config
file. Here's our .csproj file which also does not have significant change which would affect this issue.
Upvotes: 0
Reputation: 3635
In my case I am running an Angular app on an Azure hosted Linux box, the previously mentioned hash location strategy worked, but having the #
in the URL wasn't what was wanted. Adding --spa
to the configuration startup command allowed manually typing URLs. So my command is now this
pm2 serve /home/site/wwwroot/ --no-daemon --spa
More information on Azure deployment with PM2
Upvotes: 0
Reputation: 1300
Disclaimer: this fix works with Alpha44
I had the same issue and solved it by implementing the HashLocationStrategy listed in the Angular.io API Preview.
https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html
Start by importing the necessary directives
import {provide} from 'angular2/angular2';
import {
ROUTER_PROVIDERS,
LocationStrategy,
HashLocationStrategy
} from 'angular2/router';
And finally, bootstrap it all together like so
bootstrap(AppCmp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, {useClass: HashLocationStrategy})
]);
Your route will appear as http://localhost/#/route and when you refresh, it will reload at it's proper place.
Upvotes: 69
Reputation: 9
You can use location strategy, Add useHash: true
in routing file.
imports: [RouterModule.forRoot(routes, { useHash: true })]
Upvotes: 0
Reputation: 506
My server is Apache, what I did to fix 404 when refreshing or deep linking is very simple. Just add one line in apache vhost config:
ErrorDocument 404 /index.html
So that any 404 error will be redirected to index.html, which is what angular2 routing wants.
The whole vhost file example:
<VirtualHost *:80>
ServerName fenz.niwa.local
DirectoryIndex index.html
ErrorDocument 404 /index.html
DocumentRoot "/Users/zhoum/Documents/workspace/fire/fire_service/dist"
ErrorLog /Users/zhoum/Documents/workspace/fire/fire_service/logs/fenz.error.log
CustomLog /Users/zhoum/Documents/workspace/fire/fire_service/logs/fenz.access.log combined
<Directory "/Users/zhoum/Documents/workspace/fire/fire_service/dist">
AllowOverride All
Options Indexes FollowSymLinks
#Order allow,deny
#Allow from All
Require all granted
</Directory>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Accept-Encoding"
</VirtualHost>
No matter what server you are using, I think the whole point is finding out the ways to config the server to redirect 404 to your index.html.
Upvotes: 5
Reputation: 970
If you are using Apache or Nginx as a server you have to create a .htaccess
(if not created before) and "On" RewriteEngine
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html
Upvotes: 7
Reputation: 3979
The error you are seeing is because you are requesting http://localhost/route which doesn't exist. According to Simon.
When using html5 routing you need to map all routes in your app(currently 404) to index.html in your server side. Here are some options for you:
using live-server: https://www.npmjs.com/package/live-server
$live-server --entry-file=index.html`
using nginx: http://nginx.org/en/docs/beginners_guide.html
error_page 404 /index.html
Tomcat - configuration of web.xml. From Kunin's comment
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
Upvotes: 152
Reputation: 466
If you are using Apache or Nginx as a server you need to create a .htaccess
<IfModule mime_module>
AddHandler application/x-httpd-ea-php72 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
<IfModule mod_rewrite.c>
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]
</IfModule>
Upvotes: 0
Reputation: 69
You can use this solution for mean application, I used ejs as view engine:
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(function (req, res, next) {
return res.render('index.html');
});
and also set in angular-cli.json
"apps": [
{
"root": "src",
"outDir": "views",
it will work fine instead of
app.get('*', function (req, res, next) {
res.sendFile('dist/index.html', { root: __dirname });
});
its creating issue with get db calls and returning index.html
Upvotes: 3
Reputation: 116
i Just adding .htaccess in root.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ ./index.html
</IfModule>
here i just add dot '.'(parent directory) in /index.html to ./index.html
make sure your index.html file in base path is main directory path and set in build of project.
Upvotes: 2
Reputation: 272
I think you are getting 404 because your are requesting http://localhost/route which doesn't exist on tomcat server. As Angular 2 uses html 5 routing by default rather than using hashes at the end of the URL, refreshing the page looks like a request for a different resource.
When using angular routing on tomcat you need to make sure that your server will map all routes in your app to your main index.html while refreshing the page. There are multiple way to resolve this issue. Whichever one suits you you can go for that.
1) Put below code in web.xml of your deployment folder :
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
2) You can also try using HashLocationStrategy with # in the URL for routes :
Try using:
RouterModule.forRoot(routes, { useHash: true })
Instead of:
RouterModule.forRoot(routes)
With HashLocationStrategy your urls gonna be like:
3) Tomcat URL Rewrite Valve : Re-write the url's using a server level configuration to redirect to index.html if the resource is not found.
3.1) Inside META-INF folder create a file context.xml and copy the below context inside it.
<? xml version='1.0' encoding='utf-8'?>
<Context>
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
</Context>
3.2) Inside WEB-INF, create file rewrite.config(this file contain the rule for URL Rewriting and used by tomcat for URL rewriting). Inside rewrite.config, copy the below content:
RewriteCond %{SERVLET_PATH} !-f
RewriteRule ^/(.*)$ /index.html [L]
Upvotes: 1
Reputation: 1608
Just adding .htaccess in root resolved 404 while refreshing the page in angular 4 apache2.
<IfModule mod_rewrite.c>
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]
</IfModule>
Upvotes: 1
Reputation: 51
Add imports:
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
And in NgModule provider, add:
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
In main index.html File of the App change the base href to ./index.html
from /
The App when deployed in any server will give a real url for the page which can be accessed from any external application.
Upvotes: 1
Reputation: 442
for angular 5 quick fix, edit app.module.ts and add {useHash:true}
after the appRoutes.
@NgModule(
{
imports:[RouterModule.forRoot(appRoutes,{useHash:true})]
})
Upvotes: 4
Reputation: 1582
I fixed this (using Java / Spring backend) by adding a handler that matches everything defined in my Angular routes, that sends back index.html instead of a 404. This then effectively (re)bootstraps the application and loads the correct page. I also have a 404 handler for anything that isn't caught by this.
@Controller ////don't use RestController or it will just send back the string "index.html"
public class Redirect {
private static final Logger logger = LoggerFactory.getLogger(Redirect.class);
@RequestMapping(value = {"comma", "sep", "list", "of", "routes"})
public String redirectToIndex(HttpServletRequest request) {
logger.warn("Redirect api called for URL {}. Sending index.html back instead. This will happen on a page refresh or reload when the page is on an Angular route", request.getRequestURL());
return "/index.html";
}
}
Upvotes: 0
Reputation: 4665
Angular apps are perfect candidates for serving with a simple static HTML server. You don't need a server-side engine to dynamically compose application pages because Angular does that on the client-side.
If the app uses the Angular router, you must configure the server to return the application's host page (index.html) when asked for a file that it does not have.
A routed application should support "deep links". A deep link is a URL that specifies a path to a component inside the app. For example, http://www.example.com/heroes/42 is a deep link to the hero detail page that displays the hero with id: 42.
There is no issue when the user navigates to that URL from within a running client. The Angular router interprets the URL and routes to that page and hero.
But clicking a link in an email, entering it in the browser address bar, or merely refreshing the browser while on the hero detail page — all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router.
A static server routinely returns index.html when it receives a request for http://www.example.com/. But it rejects http://www.example.com/heroes/42 and returns a 404 - Not Found error unless it is configured to return index.html instead
If this issue occurred in production, follow below steps
1) Add a Web.Config file in the src folder of your angular application. Place below code in it.
<configuration>
<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>
</configuration>
2) Add a reference to it in angular-cli.json. In angular-cli.json put Web.config in assets block as shown below.
"assets": [
"assets",
"favicon.ico",
"Web.config"
],
3) Now you can build the solution for production using
ng build --prod
This will create a dist folder. The files inside dist folder are ready for deployment by any mode.
Upvotes: 3
Reputation: 19640
This is not a permanent Fix for the problem but more like a workaround or hack
I had this very same issue when deploying my Angular App to gh-pages. First i was greeted with 404 messages when Refreshing my pages on gh-pages.
Then as what @gunter pointed out i started using HashLocationStrategy
which was provided with Angular 2 .
But that came with it's own set of problems the #
in the url it was really bad made the url look wierd like this https://rahulrsingh09.github.io/AngularConcepts/#/faq
.
I started researching out about this problem and came across a blog. I tried giving it a shot and it worked .
Here is what i did as mentioned in that blog.
You’ll need to start by adding a 404.html file to your gh-pages repo that contains an empty HTML document inside it – but your document must total more than 512 bytes (explained below). Next put the following markup in your 404.html page’s head element:
<script>
sessionStorage.redirect = location.href;
</script>
<meta http-equiv="refresh" content="0;URL='/REPO_NAME_HERE'"></meta>
This code sets the attempted entrance URL to a variable on the standard sessionStorage object and immediately redirects to your project’s index.html page using a meta refresh tag. If you’re doing a Github Organization site, don’t put a repo name in the content attribute replacer text, just do this: content="0;URL='/'"
In order to capture and restore the URL the user initially navigated to, you’ll need to add the following script tag to the head of your index.html page before any other JavaScript acts on the page’s current state:
<script>
(function(){
var redirect = sessionStorage.redirect;
delete sessionStorage.redirect;
if (redirect && redirect != location.href) {
history.replaceState(null, null, redirect);
}
})();
</script>
This bit of JavaScript retrieves the URL we cached in sessionStorage over on the 404.html page and replaces the current history entry with it.
Reference backalleycoder Thanks to @Daniel for this workaround.
Now the above URL changes to https://rahulrsingh09.github.io/AngularConcepts/faq
Upvotes: 0
Reputation: 657937
Angular by default uses HTML5 pushstate (PathLocationStrategy
in Angular slang).
You either need a server that processes all requests like it were requesting index.html
or you switch to HashLocationStrategy
(with # in the URL for routes) https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html
See also https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/
To switch to HashLocationStrategy
use
update for >= RC.5 and 2.0.0 final
import {HashLocationStrategy, LocationStrategy} from '@angular/common';
@NgModule({
declarations: [AppCmp],
bootstrap: [AppCmp],
imports: [BrowserModule, routes],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
]);
or shorter with useHash
imports: [RouterModule.forRoot(ROUTER_CONFIG, {useHash: true}), ...
ensure you have all required imports
For the new (RC.3) router
<base href=".">
can cause 404 as well.
It requires instead
<base href="/">
update for >= RC.x
bootstrap(AppCmp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, {useClass: HashLocationStrategy})
// or since RC.2
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
import {provide} from '@angular/core';
import {
PlatformLocation,
Location,
LocationStrategy,
HashLocationStrategy,
PathLocationStrategy,
APP_BASE_HREF}
from '@angular/common';
update for >= beta.16 Imports have changed
import {BrowserPlatformLocation} from '@angular/platform-browser';
import {provide} from 'angular2/core';
import {
// PlatformLocation,
// Location,
LocationStrategy,
HashLocationStrategy,
// PathLocationStrategy,
APP_BASE_HREF}
from 'angular2/router';
import {BrowserPlatformLocation} from 'angular2/src/router/location/browser_platform_location';
< beta.16
import {provide} from 'angular2/core';
import {
HashLocationStrategy
LocationStrategy,
ROUTER_PROVIDERS,
} from 'angular2/router';
See also https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta16-2016-04-26 breaking-changes
Upvotes: 50
Reputation: 37
The answer is quite tricky. If you use a plain old Apache Server (or IIS), you get the problem because the Angular pages do not exist for real. They are "computed" from the Angular route.
There are several ways to fix the issue. One is to use the HashLocationStrategy offered by Angular. But a sharp sign is added in the URL. This is mainly for compatibility with Angular 1 (I assume). The fact is the part after the sharp is not part of the URL (then the server resolves the part before the "#" sign). That can be perfect.
Here an enhanced method (based on the 404 trick). I assume you have a "distributed" version of your angular application (ng build --prod
if you use Angular-CLI) and you access the pages directly with your server and PHP is enabled.
If your website is based on pages (Wordpress for example) and you have only one folder dedicated to Angular (named "dist" in my example), you can do something weird but, at the end, simple. I assume you have stored your Angular pages in "/dist" (with the according <BASE HREF="/dist/">
). Now use a 404 redirection and the help of PHP.
In your Apache configuration (or in the .htaccess
file of your angular application directory), you must add ErrorDocument 404 /404.php
The 404.php will start with the following code:
<?php
$angular='/dist/';
if( substr($_SERVER['REQUEST_URI'], 0, strlen($angular)) == $angular ){
$index = $_SERVER['DOCUMENT_ROOT'] . $angular . "index.html";
http_response_code(200);
include $index;
die;
}
// NOT ANGULAR...
echo "<h1>Not found.</h1>"
where $angular
is the value stored in the HREF of your angular index.html
.
The principle is quite simple, if Apache does not find the page, a 404 redirection is made to the PHP script. We just check if the page is inside the angular application directory. If it is the case, we just load the index.html directly (without redirecting): this is necessary to keep the URL unchanged. We also change the HTTP code from 404 to 200 (just better for crawlers).
What if the page does not exist in the angular application? Well, we use the "catch all" of the angular router (see Angular router documentation).
This method works with an embedded Angular application inside a basic website (I think it will be the case in future).
NOTES:
mod_redirect
(by rewriting the URLs) is not at all a good solution because files (like assets) have to be really loaded then it is much more risky than just using the "not found" solution.ErrorDocument 404 /dist/index.html
works but Apache is still responding with a 404 error code (which is bad for crawlers).Upvotes: 0
Reputation: 3671
2017-July-11: Since this is linked from a question having this problem but using Angular 2 with Electron, I'll add my solution here.
All I had to do was remove <base href="./">
from my index.html and Electron started reloading the page again successfully.
Upvotes: 1
Reputation: 21
You can try out below. It works for me!
main.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
...
export class MainComponent implements OnInit {
constructor(private router: Router) {
let path: string = window.location.hash;
if (path && path.length > 0) {
this.router.navigate([path.substr(2)]);
}
}
public ngOnInit() { }
}
You can further enhance path.substr(2) to split into router parameters. I'm using angular 2.4.9
Upvotes: 2
Reputation: 21
The best solution of resolve the "router-not-working-on-reloading-the-browser" is that we should use spa-fall back. If you are using angular2 application with asp.net core then we need to defined it on "StartUp.cs" page. under MVC routs. I am attaching the code.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
});
Upvotes: 0
Reputation: 11
If you want to use PathLocationStrategy :
Single page application with Java EE/Wildfly: server-side configuration
Upvotes: 1
Reputation: 1069
If you want to be able to enter urls in browser without configuring your AppServer to handle all requests to index.html, you must use HashLocationStrategy.
The easiest way to configure is using:
RouterModule.forRoot(routes, { useHash: true })
Instead of:
RouterModule.forRoot(routes)
With HashLocationStrategy your urls gonna be like:
http://server:port/#/path
Upvotes: 12
Reputation: 162
This is not the right answer but On-refresh you can redirect all dead calls to Homepage by sacrificing 404 page it's a temporary hack just replay following on 404.html file
<!doctype html>
<html>
<head>
<script type="text/javascript">
window.location.href = "http://" + document.location.host;
</script>
</head>
</html>
Upvotes: 0
Reputation: 1041
I checked in angular 2 seed how it works.
You can use express-history-api-fallback to redirect automatically when a page is reload.
I think it's the most elegant way to resolve this problem IMO.
Upvotes: 1
Reputation: 1287
I wanted to preserve the URL path of sub pages in HTML5 mode without a redirect back to index and none of the solutions out there told me how to do this, so this is how I accomplished it:
Create simple virtual directories in IIS for all your routes and point them to the app root.
Wrap your system.webServer in your Web.config.xml with this location tag, otherwise you will get duplicate errors from it loading Web.config a second time with the virtual directory:
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<defaultDocument enabled="true">
<files>
<add value="index.html" />
</files>
</defaultDocument>
</system.webServer>
</location>
</configuration>
Upvotes: 1
Reputation: 797
I had the same problem with using webpack-dev-server. I had to add the devServer option to my webpack.
// in webpack
devServer: {
historyApiFallback: true,
stats: 'minimal'
}
Upvotes: 7
Reputation: 31
For those of us struggling through life in IIS: use the following PowerShell code to fix this issue based on the official Angular 2 docs (that someone posted in this thread? http://blog.angular-university.io/angular2-router/)
Import-WebAdministration
# Grab the 404 handler and update it to redirect to index.html.
$redirect = Get-WebConfiguration -filter "/system.WebServer/httperrors/error[@statusCode='404']" -PSPath IIS:\Sites\LIS
$redirect.path = "/index.html"
$redirect.responseMode = 1
# shove the updated config back into IIS
Set-WebConfiguration -filter "/system.WebServer/httperrors/error[@statusCode='404']" -PSPath IIS:\Sites\LIS -value $redirect
This redirects the 404 to the /index.html file as per the suggestion in the Angular 2 docs (link above).
Upvotes: 2
Reputation: 43117
This is a common situation in all router versions if you are using the default HTML location strategy.
What happens is that the URL on the browser bar is a normal full HTML url, like for example: http://localhost/route
.
So when we hit Enter in the browser bar, there is an actual HTTP request sent to the server to get a file named route
.
The server does not have such file, and neither something like express is configured on the server to handle the request and provide a response, so the server return 404 Not Found, because it could not find the route
file.
What we would like is for the server to return the index.html
file containing the single page application. Then the router should kick in and process the /route
url and display the component mapped to it.
So to fix the issue we need to configure the server to return index.html
(assuming that is the name of your single page application file) in case the request could not be handled, as opposed to a 404 Not Found.
The way to do this will depend on the server side technology being used. If its Java for example you might have to write a servlet, in Rails it will be different, etc.
To give a concrete example, if for example you are using NodeJs, you would have to write a middleware like this:
function sendSpaFileIfUnmatched(req,res) {
res.sendFile("index.html", { root: '.' });
}
And then register it at the very end of the middleware chain:
app.use(sendSpaFileIfUnmatched);
This will serve index.html
instead of returning a 404, the router will kick in and everything will work as expected.
Upvotes: 23