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

问题描述 投票:168回答:32

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

你能帮我弄清楚这个错误发生的原因吗?

angular angular2-routing
32个回答
133
投票

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

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

  1. 使用live-server: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>

5
投票

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

ErrorDocument 404 /index.html

因此任何404错误都将被重定向到index.html,这就是angular2路由所需要的。

整个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的方法。


5
投票

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

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

4
投票

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

试试这个而不是其他或错误的路线。它对我有用,不确定,但似乎正在进行中。面对问题时,我自己绊倒了。

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

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

但是,如果您的HTML或Web脚本不是SPA,请记住配置您的服务器文件夹和访问权限。否则你将面临问题。对我来说,面对像你这样的问题,它是服务器配置和上面的混合。


3
投票

您可以将此解决方案用于平均应用程序,我使用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来创建问题


2
投票

对于我们这些在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文件。


2
投票

你可以在下面试试。这个对我有用!

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)以拆分为路由器参数。我正在使用棱角2.4.9


2
投票

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)在角度应用程序的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": [
    "assets",
    "favicon.ico",
    "Web.config"
  ],

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

ng build --prod

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


1
投票

我想在HTML5模式下保留子页面的URL路径而不重定向到索引,并且没有任何解决方案告诉我如何执行此操作,所以这就是我完成它的方式:

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

1
投票

我检查了角2种子是如何工作的。

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

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


1
投票

如果要使用PathLocationStrategy:

  • Wildfly配置: 创建要放在WEB-INF中的undertow-handlers.conf文件 内容:(排除你的休息终点!) 正则表达式['(./ overview /?.?$)']而不是正则表达式['(./端点。)'] - >重写['/ index.html'] 正则表达式['(./ deployments /?.?$)']而不是正则表达式['(./端点。)'] - >重写['/ index.html']

Single page application with Java EE/Wildfly: server-side configuration


62
投票

免责声明:此修复程序适用于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(AppCmp, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

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

希望有所帮助!


1
投票

只需在root 4中添加.htaccess解析404,同时在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>

1
投票

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

在tomcat上使用角度路由时,您需要确保服务器在刷新页面时将应用程序中的所有路径映射到主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你的网址将是:

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中,创建文件rewrite.config(该文件包含URL重写的规则,并由tomcat用于URL重写)。在rewrite.config里面,复制以下内容:

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

1
投票

我只是在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文件是主目录路径并在项目构建中设置。


0
投票

这不是正确的答案,但是On-refresh你可以通过牺牲404页面将所有死方的呼叫重定向到主页,这是一个临时黑客,只需重播404.html文件

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

0
投票

解决“路由器不能正在重新加载浏览器”的最佳解决方案是我们应该使用spa-fall。如果您正在使用带有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" });
        });

0
投票

2017年7月11日:由于这是linked从一个有这个问题的问题但是使用Angular 2和Electron,我会在这里添加我的解决方案。

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


0
投票

答案非常棘手。如果您使用普通的旧Apache服务器(或IIS),则会出现问题,因为Angular页面不存在真实存在。它们是从Angular路线“计算”出来的。

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

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

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

在Apache配置中(或在角度应用程序目录的.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是存储在角度index.html的HREF中的值。

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

如果角度应用程序中不存在页面怎么办?好吧,我们使用角度路由器的“全部捕获”(参见Angular路由器文档)。

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

笔记:

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

0
投票

这不是问题的永久性修复,而更像是变通方法或黑客攻击

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

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

但这带来了它自己的一系列问题#在网址中它真的很糟糕使得网址看起来像这个https://rahulrsingh09.github.io/AngularConcepts/#/faq一样奇怪。

我开始研究这个问题并且发现了一个博客。我试过给它一个镜头,它工作。

这就是我在博客中所提到的。

您需要首先将一个404.html文件添加到您的gh-pages repo中,其中包含一个空的HTML文档 - 但您的文档总数必须超过512个字节(如下所述)。接下来将以下标记放在404.html页面的head元素中:

<script>
  sessionStorage.redirect = location.href;
</script>
<meta http-equiv="refresh" content="0;URL='/REPO_NAME_HERE'"></meta>

此代码将尝试的入口URL设置为标准sessionStorage对象上的变量,并使用元刷新标记立即重定向到项目的index.html页面。如果您正在使用Github Organization站点,请不要在内容属性替换器文本中添加repo名称,只需执行以下操作:content =“0; URL ='/'”

为了捕获和恢复用户最初导航到的URL,您需要在页面的当前状态上执行任何其他JavaScript操作之前,将以下脚本标记添加到index.html页面的头部:

<script>
  (function(){
    var redirect = sessionStorage.redirect;
    delete sessionStorage.redirect;
    if (redirect && redirect != location.href) {
      history.replaceState(null, null, redirect);
    }
  })();
</script>

这一段JavaScript检索我们在404.html页面上缓存在sessionStorage中的URL,并用它替换当前的历史条目。

参考backalleycoder感谢@Daniel的解决方法。

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


0
投票

我修改了这个(使用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";
    }
}

0
投票

添加进口:

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

在NgModule提供程序中,添加:

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

在应用程序的主index.html文件中,将基础href从./index.html更改为/

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


43
投票

默认情况下,Angular使用HTML5 pushstate(Angular slang中的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';

<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破坏性变化


0
投票

如果您使用nginx Web服务器来提供角度应用程序,则只需在nginx conf文件的服务器块中添加try_files $uri $uri/ /index.html;即可。对于ubuntu服务器,此文件名为default.conf,可以在/etc/nginx/conf.d找到

    /etc/nginx/conf.d # vi default.conf

        server {
            listen       80;
            server_name  localhost;

            #charset koi8-r;
            #access_log  /var/log/nginx/host.access.log  main;

            location / {
                root   /usr/share/nginx/html;
                try_files $uri $uri/ /index.html;
                index  index.html index.htm;
            }
        }

26
投票

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

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


18
投票

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

会发生什么是浏览器栏上的URL是一个普通的完整HTML网址,例如:http://localhost/route

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

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

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

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

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

举一个具体的例子,例如,如果您使用的是NodeJ,则必须编写如下的中间件:

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

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

app.use(sendSpaFileIfUnmatched);

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


13
投票

确保将其放在index.html的head元素中:

<base href="/">

Angular2 Example文档中的Routing & Navigation使用头部中的以下代码(它们解释了为什么在文档的实例示例中):

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

刷新页面时,这将动态地将基本href设置为当前document.location。我可以看到这导致一些混淆,人们浏览文档并尝试复制plunker。


9
投票

如果您希望能够在浏览器中输入URL而不将AppServer配置为处理对index.html的所有请求,则必须使用HashLocationStrategy。

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

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

代替:

RouterModule.forRoot(routes)

使用HashLocationStrategy你的网址将是:

http://server:port/#/path

7
投票

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

Solution:

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

7
投票

如果您使用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

© www.soinside.com 2019 - 2024. All rights reserved.