Angular 2.0 的路由器在重新加载浏览器时不起作用

我使用的是 Angular 2.0.0-alpha.30 的版本。当重定向到不同的路由并刷新浏览器时,显示找不到 /route。

能帮我弄清楚为什么会发生这个错误吗?

118563 次浏览

我认为你看到的错误是因为你正在请求不存在的http://localhost/route。您需要确保您的服务器将所有请求映射到您的主index.html页面。

由于Angular 2默认使用html5路由,而不是在url末尾使用散列,因此刷新页面看起来就像对不同资源的请求。

免责声明:此修复适用于Alpha44

我也有同样的问题,并通过实现Angular中列出的HashLocationStrategy来解决它。io API预览。

https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html < a href = " https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html " > < / >

首先导入必要的指令

import {provide} from 'angular2/angular2';
import {
ROUTER_PROVIDERS,
LocationStrategy,
HashLocationStrategy
} from 'angular2/router';

最后,像这样把它们引导到一起

bootstrap(AppCmp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

您的路由将显示为http://localhost/#/route,当您刷新时,它将在适当的位置重新加载。

希望有帮助!

西蒙的答案对我来说是正确的。我添加了以下代码:

app.get('*', function(req, res, next) {
res.sendfile("dist/index.html");
});

您看到的错误是因为您请求的是不存在的http://localhost/route。根据西蒙

当使用html5路由时,你需要在服务器端将应用程序中的所有路由(当前404)映射到index.html。这里有一些适合你的选择:

  1. 使用live-server: https://www.npmjs.com/package/live-server

    $live-server --entry-file=index.html`
    
  2. using nginx: http://nginx.org/en/docs/beginners_guide.html

    error_page 404 /index.html
    
  3. Tomcat配置web.xml。来自Kunin的注释

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

确保它被放在index.html的head元素中:

<base href="/">

Angular2 路由,导航文档中的例子在头部使用了以下代码(他们在文档的现场示例注释中解释了原因):

<script>document.write('<base href="' + document.location + '" />');</script>

当你刷新一个页面时,这将动态地将base href设置为当前的document.location。我可以看到这引起了一些混乱的人略读文档,并试图复制活塞。

我甚至认为服务器配置不是SPA的解决方案。你不想重新加载一个角SPA,如果一个错误的路由进来,对吗?所以我不会依赖于服务器路由并重定向到其他路由,但是我会让index.html处理angular应用路径的所有angular路由请求。

尝试这样做,而不是其他或错误的路线。它对我有用,不确定,但似乎还在进行中。在面对一个问题时,我自己也遇到了这个问题。

@RouteConfig([
{ path: '/**', redirectTo: ['MycmpnameCmp'] },
...
}
])

https://github.com/angular/angular/issues/4055

但是,请记住配置您的服务器文件夹和访问权限,以防您有HTML或web脚本,而不是SPA。否则你将面临问题。对我来说,当遇到像你这样的问题时,它是服务器配置和以上的混合。

Angular默认使用HTML5的pushstate (Angular俚语中的PathLocationStrategy) 你要么需要一个服务器来处理所有请求,就像它请求index.html一样,要么你切换到HashLocationStrategy(在URL中有#用于路由)https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html

另见https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/

切换到HashLocationStrategy使用

更新>= RC.5和2.0.0 final

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


@NgModule({
declarations: [AppCmp],
bootstrap: [AppCmp],
imports: [BrowserModule, routes],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
]);

或更短的useHash

imports: [RouterModule.forRoot(ROUTER_CONFIG, {useHash: true}), ...

确保您有所有必需的导入

用于新的(RC.3)路由器

<base href=".">

也可能导致404。

相反,它需要

<base href="/">

更新>= 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';

更新>= beta.16导入已经改变

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

& lt;beta.16

import {provide} from 'angular2/core';
import {
HashLocationStrategy
LocationStrategy,
ROUTER_PROVIDERS,
} from 'angular2/router';

请参见https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta16-2016-04-26 breaking-changes

如果您使用默认的HTML定位策略,这是所有路由器版本的常见情况。

浏览器栏上的URL是一个正常的完整HTML URL,例如:http://localhost/route

因此,当我们在浏览器栏中按下Enter键时,就会有一个实际的HTTP请求发送到服务器,以获取一个名为route的文件。

服务器没有这样的文件,服务器上也没有配置类似express的文件来处理请求并提供响应,因此服务器返回404 not Found,因为它找不到route文件。

我们希望服务器返回包含单页应用程序的index.html文件。然后路由器应该介入并处理/route url并显示映射到它的组件。

因此,为了解决这个问题,我们需要配置服务器返回index.html(假设这是您的单页应用程序文件的名称),以防请求无法处理,而不是404 not Found。

这样做的方式取决于所使用的服务器端技术。如果它是Java,例如,你可能需要写一个servlet,在Rails中就会不同,等等。

举个具体的例子,如果你正在使用NodeJs,你必须写一个这样的中间件:

function sendSpaFileIfUnmatched(req,res) {
res.sendFile("index.html", { root: '.' });
}

然后在中间件链的最末端注册它:

app.use(sendSpaFileIfUnmatched);

这将为index.html服务,而不是返回404,路由器将启动,一切都将按预期工作。

对于我们这些在IIS中挣扎的人来说:使用下面的PowerShell代码来修复这个问题,这个问题基于Angular 2的官方文档(有人在这个帖子中发布了这个文档?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

这将按照Angular 2文档中的建议(如上链接)将404重定向到/index.html文件。

我在使用webpack-dev-server时也遇到了同样的问题。我必须在webpack中添加devServer选项。

解决方案:

// in webpack
devServer: {
historyApiFallback: true,
stats: 'minimal'
}

我想在HTML5模式下保留子页面的URL路径,而不是重定向回索引,没有任何解决方案告诉我如何做到这一点,所以这就是我如何完成的:

在IIS中为所有路由创建简单的虚拟目录,并将它们指向应用根目录。

包装你的系统。在你的Web.config.xml中的webServer中使用这个位置标记,否则你将在加载Web时得到重复的错误。第二次配置虚拟目录:

<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<defaultDocument enabled="true">
<files>
<add value="index.html" />
</files>
</defaultDocument>
</system.webServer>
</location>
</configuration>

我检查了angular 2 seed是如何工作的。

当页面重新加载时,可以使用express-history-api-fallback自动重定向。

我认为这是解决这个问题最优雅的方式。

这不是正确的答案,但在刷新时,你可以通过牺牲404页面重定向到主页,这是一个临时的黑客,只是重放404.html文件

<!doctype html>
<html>
<head>
<script type="text/javascript">
window.location.href = "http://" + document.location.host;
</script>
</head>
</html>

如果你想在浏览器中输入url,而不配置你的AppServer来处理所有对index.html的请求,你必须使用HashLocationStrategy

最简单的配置方法是使用:

RouterModule.forRoot(routes, { useHash: true })

而不是:

RouterModule.forRoot(routes)

使用HashLocationStrategy你的url会像这样:

http://server:port/#/path

如果你使用Apache或Nginx作为服务器,你必须创建.htaccess(如果之前没有创建)和"On"RewriteEngine

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html

我的服务器是Apache,我在刷新或深度链接时修复404非常简单。只需在apache vhost配置中添加一行:

ErrorDocument 404 /index.html

因此任何404错误都将被重定向到index.html,这是angular2 routing想要的。

完整的vhost文件示例:

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

无论您使用什么服务器,我认为关键在于找到配置服务器将404重定向到index.html的方法。

如果你想使用PathLocationStrategy:

  • Wildfly配置:
    • 创建undertow-handlers.conf文件,放在WEB-INF中
    • 内容:(排除其余端点!)
      • 正则表达式(“(./概述/ ?。 ?)美元”),而不是正则表达式[' (./端点。 )'] -> 重写(' / index . html)
      • 正则表达式(“(./部署/ ?。 ?)美元”),而不是正则表达式[' (./端点。) '] - >重写(' / index . html)
      • 李< / ul > < / > 李< / ul > < / >

      单页应用程序与Java EE/Wildfly:服务器端配置

解决“重新加载浏览器时路由器不工作”的最佳方案是我们应该使用spa-fall back。如果你使用的是带有asp.net核心的angular2应用程序,那么我们需要在“StartUp.cs”页面上定义它。在MVC路由下。我正在附上代码。

 app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
});

你可以试试下面的方法。这对我很管用!

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() { }
}

您可以进一步增强path.substr(2),将其拆分为路由器参数。我使用的是angular 2.4.9

你可以将这个解决方案用于普通应用程序,我使用ejs作为视图引擎:

// 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');
});

也在angular-cli。json中设置

"apps": [
{
"root": "src",
"outDir": "views",

它会工作得很好,而不是

app.get('*', function (req, res, next) {
res.sendFile('dist/index.html', { root: __dirname });
});

它创建的问题与get db调用和返回index.html

2017年7月11日:由于这个有关来自一个有这个问题的问题,但使用了带有Electron的Angular 2,我将在这里添加我的解决方案。

我所要做的就是将<base href="./">从我的index.html和电子开始重新加载页面再次成功。

答案相当棘手。如果你使用普通的Apache Server(或IIS),你就会遇到这个问题,因为Angular页面并不真实存在。它们是从Angular路由中“计算”出来的。

有几种方法可以解决这个问题。一种是使用Angular提供的HashLocationStrategy。但是在URL中添加了一个尖锐的符号。这主要是为了与Angular 1兼容(我假设)。事实上,尖符号之后的部分不是URL的一部分(那么服务器将解析“#”符号之前的部分)。这是完美的。

这里有一个增强的方法(基于404技巧)。我假设你有一个“分布式”版本的angular应用程序(如果你使用angular - cli,则为ng build --prod),你可以直接通过服务器访问页面,并且启用了PHP。

如果你的网站是基于页面的(比如Wordpress),而且你只有一个专用于Angular的文件夹(在我的例子中名为“dist”),你可以做一些奇怪但最后很简单的事情。我假设你已经将你的Angular页面存储在“/dist”中(使用<BASE HREF="/dist/">)。现在使用404重定向和PHP的帮助。

在你的Apache配置中(或者在你的angular应用目录的.htaccess文件中),你必须添加ErrorDocument 404 /404.php

404.php将以以下代码开始:

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

其中$angular是存储在你的angular index.html的HREF中的值。

原理非常简单,如果Apache没有找到该页面,则对PHP脚本进行404重定向。我们只是检查页面是否在angular应用程序目录中。如果是这样的话,我们只需直接加载index.html(不重定向):这是保持URL不变所必需的。我们还将HTTP代码从404更改为200(这对爬虫来说更好)。

如果这个页面在angular应用中不存在怎么办?好吧,我们使用angular路由器的“catch all”(参见angular路由器文档)。

这种方法适用于基本网站内的嵌入式Angular应用程序(我认为将来会是这样)。

注:

  • 试图对mod_redirect做同样的事情(通过重写url)根本不是一个好的解决方案,因为文件(如资产)必须真正加载,那么它比仅仅使用“未找到”解决方案风险大得多。
  • 只是使用ErrorDocument 404 /dist/index.html重定向工作,但Apache仍然响应404错误代码(这对爬行器不利)。

这不是一个永久性的修复问题,而更像是一个变通办法或黑客

我在把Angular应用部署到gh-pages时也遇到了同样的问题。 首先,当我在gh-pages上刷新我的页面时,我收到了404消息

然后正如@gunter指出的那样,我开始使用Angular 2提供的HashLocationStrategy

但这也带来了它自己的一组问题,url中的#,它真的很糟糕,使url看起来像https://rahulrsingh09.github.io/AngularConcepts/#/faq一样奇怪。

我开始研究这个问题,并看到了一个博客。我试过了,成功了。

以下是我在那篇博客中提到的。

你需要从添加一个404.html文件到你的gh-pages repo开始 其中包含一个空的HTML文档-但您的文档 总数必须大于512字节(如下所述)。接下来放入

.html页面头部元素中的以下标记
<script>
sessionStorage.redirect = location.href;
</script>
<meta http-equiv="refresh" content="0;URL='/REPO_NAME_HERE'"></meta>
上的一个变量设置了尝试的入口URL 标准sessionStorage对象,并立即重定向到您的 使用元刷新标记的项目的index.html页面。如果你在做 Github组织网站,不要在内容中放入回购名称 属性替换文本,只需这样做:content="0;URL= " / "

为了捕获和恢复用户最初导航的URL ,则需要将以下脚本标记添加到 index.html页面之前,任何其他JavaScript对页面的当前 状态:< / p >
<script>
(function(){
var redirect = sessionStorage.redirect;
delete sessionStorage.redirect;
if (redirect && redirect != location.href) {
history.replaceState(null, null, redirect);
}
})();
</script>
这段JavaScript代码检索我们缓存在sessionStorage中的URL 并将当前历史记录项替换为 它。< / p >

感谢@Daniel提供的解决方法。

现在上面的URL变成了https://rahulrsingh09.github.io/AngularConcepts/faq

Angular应用是一个简单的静态HTML服务器的完美选择。你不需要服务器端引擎来动态组合应用页面,因为Angular是在客户端完成的。

如果应用使用Angular路由器,你必须配置服务器,当被请求一个它没有的文件时,它会返回应用的主机页面(index.html)。

路由应用程序应该支持“深度链接”。深层链接是一个URL,它指定了应用程序内部组件的路径。例如,http://www.example.com/heroes/42是一个指向英雄详细信息页面的深层链接,该页面显示id: 42的英雄。

当用户从正在运行的客户机中导航到该URL时,不会出现任何问题。Angular的路由器会解释URL并路由到那个页面和英雄。

但是点击电子邮件中的链接,在浏览器地址栏中输入链接,或者只是在英雄详情页面上刷新浏览器——所有这些操作都是由浏览器自己处理的,而不是运行中的应用程序。浏览器直接向服务器请求该URL,绕过路由器。

静态服务器通常在接收到http://www.example.com/请求时返回index.html。但是它会拒绝http://www.example.com/heroes/42并返回404 - Not Found错误,除非它被配置为返回index.html

如果在生产中出现此问题,请执行以下步骤

1)添加一个网页。angular应用程序src文件夹中的配置文件。把下面的代码放在里面。

<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)在angular-cli.json中添加一个引用。在angular-cli。json put Web。在资产块中配置如下所示。

"assets": [
"assets",
"favicon.ico",
"Web.config"
],

3)现在您可以构建用于生产的解决方案

ng build --prod

这将创建一个dist文件夹。dist文件夹中的文件可以通过任何模式部署。

我通过添加一个处理程序来解决这个问题(使用Java / Spring后端),该处理程序匹配Angular路由中定义的所有内容,返回index.html而不是404。这将有效地(重新)引导应用程序并加载正确的页面。我还有一个404处理程序,用于任何没有被此方法捕获的东西。

@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";
}
}

对于angular 5的快速修复,编辑app.module.ts并在appRoutes之后添加{useHash:true}

@NgModule(
{
imports:[RouterModule.forRoot(appRoutes,{useHash:true})]
})

增加进口:

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

在NgModule提供程序中添加:

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

在App的main index.html文件中,将base href从/更改为./index.html

当应用程序部署在任何服务器上时,将为页面提供一个真实的url,可以从任何外部应用程序访问。

在angular 4 apache2中刷新页面时,只要在根目录中添加. htaccess就能解决404问题。

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

我认为你会得到404,因为你正在请求在tomcat服务器上不存在的http://localhost/route。由于Angular 2默认使用html 5路由,而不是在URL末尾使用散列,因此刷新页面看起来像是对不同资源的请求。

当在tomcat上使用angular路由时,你需要确保你的服务器在刷新页面时将应用中的所有路由映射到你的主index.html。有多种方法可以解决这个问题。哪个适合你,你就选哪个。

1)将以下代码放在部署文件夹的web.xml中:

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

2)你也可以尝试在路由的URL中使用HashLocationStrategy和#:

尝试使用:

RouterModule。forRoot(routes, {useHash: true})

而不是:

RouterModule.forRoot(路线)

使用HashLocationStrategy,你的url会像这样:

http://localhost/#/route

3) Tomcat URL重写阀:如果没有找到资源,使用服务器级配置重写URL重定向到index.html。

3.1)在META-INF文件夹中创建一个文件context.xml,并将下面的上下文复制到其中。

<? xml version='1.0' encoding='utf-8'?>
<Context>
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
</Context>

3.2)在WEB-INF中,创建文件重写。config(该文件包含URL重写规则,tomcat使用该文件进行URL重写)。在重写。配置后,复制以下内容:

  RewriteCond %{SERVLET_PATH} !-f
RewriteRule ^/(.*)$ /index.html [L]

我只是在根目录下添加了。htaccess。

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

这里我添加了。''(父目录)在/index.html到。/index.html
确保你的index.html文件的基本路径是主目录路径,并在项目的构建中设置

如果你使用Apache或Nginx作为服务器,你需要创建一个。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>

您可以使用定位策略,在路由文件中添加useHash: true

imports: [RouterModule.forRoot(routes, { useHash: true })]