Angular 2.0 路由器无法重新加载浏览器

Angular 2.0 router not working on reloading the browser

我正在使用 Angular 2.0.0-alpha.30 版本。当重定向到不同的路由时,然后刷新浏览器,它显示 Cannot GET /route.

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

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

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

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

我遇到了同样的问题,并通过实施 Angular.io API 预览中列出的 HashLocationStrategy 解决了这个问题。

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 像这样

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

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

希望对您有所帮助!

西蒙的回答对我来说是正确的。我添加了这段代码:

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

The error you are seeing is because you are requesting http://localhost/route which doesn't exist. According to .

使用 html5 路由时,您需要将应用中的所有路由(当前为 404)映射到服务器端的 index.html。以下是一些供您选择的选项:

  1. 使用实时服务器:https://www.npmjs.com/package/live-server

    $live-server --entry-file=index.html`
    
  2. 使用 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:

的头部元素中
<base href="/">

Example in the Angular2 Routing & Navigation 文档在头部使用了以下代码(他们在文档的实时示例注释中解释了原因):

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

当您刷新页面时,这会将基本 href 动态设置为您当前的 document.location。我可以看到这会给浏览文档并尝试复制 plunker 的人带来一些混乱。

我什至认为服务器配置不是 SPA 的解决方案。如果出现错误的路线,您不想再次重新加载 angular SPA,是吗?所以我不会依赖服务器路由并重定向到其他路由但是是的我会让 index.html 处理 angular 应用程序路径的 angular 路由的所有请求。

尝试这个而不是其他或错误的路线。它对我有用,不确定但似乎正在进行中。遇到问题时自己偶然发现了这个。

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

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

但是请记住配置您的服务器文件夹和访问权限,以防您有 HTML 或非 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';

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 重大更改

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

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

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

的文件

服务器没有这样的文件,服务器上也没有配置类似express的东西来处理请求并提供响应,所以服务器return 404 Not Found,因为找不到route 文件。

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

因此,为了解决这个问题,我们需要将服务器配置为 return index.html(假设这是您的单页应用程序文件的名称),以防无法处理请求,因为反对 404 未找到。

执行此操作的方式取决于所使用的服务器端技术。例如,如果它 Java 您可能必须编写一个 servlet,在 Rails 中它会有所不同,等等

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

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

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

app.use(sendSpaFileIfUnmatched);

这将提供 index.html 而不是 return 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 文档(上面的 link)中的建议,这会将 404 重定向到 /index.html 文件。

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

解决方案:

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

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

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

用这个位置标签将你的 system.webServer 包裹在你的 Web.config.xml 中,否则你会在第二次加载 Web.config 虚拟目录时收到重复错误:

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

我查看了 angular 2 种子的工作原理。

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

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

这不是正确的答案,但在刷新时,您可以通过牺牲 404 页面将所有无效调用重定向到主页,这是一个临时 hack,只是在 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 路由想要的。

整个虚拟主机文件示例:

<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.[= 的方法12=]

如果你想使用 PathLocationStrategy :

  • Wildfly 配置:
    • 创建undertow-handlers.conf文件放在WEB-INF
    • 内容:(不包括您的其余端点!)
      • regex['(./overview/?.?$)'] 而不是 regex['(./endpoints. )'] -> 重写['/index.html']
      • regex['(./deployments/?.?$)'] 而不是 regex['(./endpoints. )'] -> 重写['/index.html']

解决 "router-not-working-on-reloading-the-browser" 的最佳解决方案是我们应该使用 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 日:由于这是 linked 来自有此问题但使用 Angular 2 和 Electron 的问题,我将在此处添加我的解决方案。

我所要做的就是从我的 index.html 中删除 <base href="./">,然后 Electron 开始重新成功地重新加载页面。

答案很棘手。如果您使用普通的旧 Apache 服务器(或 IIS),则会遇到问题,因为 Angular 页面实际上并不存在。他们 "computed" 来自 Angular 路线。

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

这是一个增强的方法(基于 404 技巧)。我假设您有一个 "distributed" 版本的 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没有找到页面,404重定向到PHP脚本。我们只是检查页面是否在 angular 应用程序目录中。如果是这样,我们直接加载 index.html(不重定向):这是保持 URL 不变的必要条件。我们还将 HTTP 代码从 404 更改为 200(对爬虫来说更好)。

如果angular应用程序中不存在该页面怎么办?好吧,我们使用angular路由器的"catch all"(参见Angular路由器文档)。

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

备注:

  • 尝试对 mod_redirect 做同样的事情(通过重写 URLs)根本不是一个好的解决方案,因为必须真正加载文件(如资产)然后它是很多比仅使用 "not found" 解决方案更具风险。
  • 只需使用 ErrorDocument 404 /dist/index.html 进行重定向即可,但 Apache 仍在响应 404 错误代码(这对爬虫不利)。

这不是问题的永久修复,更像是一种解决方法或 hack

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

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

但这带来了它自己的一系列问题 url 中的 # 真的很糟糕,让 url 看起来像这样 https://rahulrsingh09.github.io/AngularConcepts/#/faq

我开始研究这个问题并发现了一个博客。我试了一下,效果很好。

这是我在那个博客中提到的所做的。

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.

参考backalleycoder感谢@Daniel 提供此解决方法。

现在上面的URL改为https://rahulrsingh09.github.io/AngularConcepts/faq

Angular 应用程序非常适合使用简单的静态 HTML 服务器进行服务。您不需要服务器端引擎来动态组合应用程序页面,因为 Angular 在客户端执行此操作。

如果应用程序使用 Angular 路由器,您必须将服务器配置为 return 应用程序的主机页面 (index.html) 当被要求提供它没有的文件时。

路由应用程序应支持 "deep links"。一个 deep link 是一个 URL,它指定了应用程序内部组件的路径。例如,http://www.example.com/heroes/42是一个深入link的英雄详情页面,显示id为:42的英雄。

当用户从 运行 客户端导航到那个 URL 时没有问题。 Angular 路由器解释 URL 并路由到该页面和英雄。

但是点击电子邮件中的 link,在浏览器地址栏中输入它,或者只是在英雄详细信息页面上刷新浏览器——所有这些操作都由浏览器本身处理,在运行申请。浏览器绕过路由器直接向服务器请求 URL。

静态服务器在收到对 http://www.example.com/ 的请求时例行地 returns index.html。但它拒绝 http://www.example.com/heroes/42 和 returns 404 - 未找到错误,除非它被配置为 return index.html 而不是

如果此问题发生在生产环境中,请按照以下步骤操作

1) 在 angular 应用程序的 src 文件夹中添加一个 Web.Config 文件。将下面的代码放入其中。

<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 中将 Web.config 放入资产块中,如下所示。

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

3) 现在您可以使用

构建生产解决方案
ng build --prod

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

我通过添加一个处理程序来解决这个问题(使用 Java / Spring 后端),该处理程序与我的 Angular 路由中定义的所有内容相匹配,它发回 index.html 而不是a 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}]

在应用程序的主要 index.html 文件中,将基本 href 从 /

更改为 ./index.html

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

在 angular 4 apache2.

中刷新页面时,只需在 root 中添加 .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 是因为您请求的 http://localhost/route 在 tomcat 服务器上不存在。由于 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(路线, { useHash: true })

而不是:

RouterModule.forRoot(路线)

使用 HashLocationStrategy,您的 url 会像:

http://localhost/#/route

3) Tomcat URL 重写 Valve :使用服务器级配置重写 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中,创建文件rewrite.config(此文件包含URL重写的规则,并被tomcat用于URL重写)。在 rewrite.config 中,复制以下内容:

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

我只是在 root 中添加 .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 })]