Angular 2: 通过浏览器刷新出现404错误
Angular 2: 404 error occur when I refresh through the browser
我是 Angular 的新手 2. 我已将我的单页应用程序存储在服务器中名为“myapp”的文件夹中。我已经将 base 中的 URL 更改为 http://example.com/myapp/`.
我的项目有两个页面。所以我实现了 Angular 2 路由。我将默认页面设置为登录。当我在浏览器中输入 http://example.com/myapp/
时,它会自动重定向到 http://example.com/myapp/login
。但是,如果刷新该页面,我会收到 404
错误,提示未找到 http://example.com/myapp/login
。
但是如果我 运行 我的项目使用精简版服务器,一切正常。在这种情况下,index.html 中的基数 URL 将是 "/"
。如何解决?
事实上,刷新应用程序时出现 404 错误是正常的,因为浏览器中的实际地址正在更新(并且没有 # / hashbang 方法)。默认情况下,HTML5 历史用于 Angular2 中的重用。
要修复 404 错误,您需要更新您的服务器,以便为您定义的每个路由路径提供 index.html
文件。
如果你想切换到HashBang方式,你需要使用这个配置:
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
import {MyApp} from './myapp';
bootstrap(MyApp, [
ROUTER_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
在这种情况下,当你刷新页面时,它会再次显示(但你的地址中会有一个#
)。
这个 link 也可以帮助您:。
希望对你有帮助,
蒂埃里
对于使用 Angular 2 rc4 或更高版本的阅读本文的人来说,LocationStrategy 似乎已从路由器移至通用。您必须从那里导入它。
还要注意 'provide' 行周围的大括号。
main.ts
// Imports for loading & configuring the in-memory web api
import { XHRBackend } from '@angular/http';
// The usual bootstrapping imports
import { bootstrap } from '@angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '@angular/http';
import { AppComponent } from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { Location, LocationStrategy, HashLocationStrategy} from '@angular/common';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
HTTP_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
更新Angular 2 最终 版本
在app.module.ts中:
添加导入:
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
并在 NgModule 提供者中添加:
{provide: LocationStrategy, useClass: HashLocationStrategy}
示例 (app.module.ts):
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent],
})
export class AppModule {}
备选
使用带有 {useHash: true} 参数的 RouterModule.forRoot。
示例:(来自 angular docs)
import { NgModule } from '@angular/core';
...
const routes: Routes = [//routes in here];
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(routes, { useHash: true })
],
bootstrap: [AppComponent]
})
export class AppModule { }
或许您可以在 root
注册 RouterModule
的同时完成此操作。您可以使用 属性 useHash:true
传递第二个对象,如下所示:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ROUTES } from './app.routes';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
RouterModule.forRoot(ROUTES ,{ useHash: true }),],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
如果您在 Visual Studio 2015 年 运行 Angular 2 到 ASP.NET 核心 1,您可能会发现 Jürgen Gutsch 的这个解决方案很有帮助。他在 a blog post 中描述了它。这对我来说是最好的解决方案。将下面提供的 C# 代码放在 Startup.cs public void Configure() 之前 app.UseStaticFiles();
app.Use( async ( context, next ) => {
await next();
if( context.Response.StatusCode == 404 && !Path.HasExtension( context.Request.Path.Value ) ) {
context.Request.Path = "/index.html";
await next();
}
});
对于真正想要 PathLocationStrategy
(即 html5Mode)而不是 HashLocationStrategy
的人(如我),请参阅第三方的 How to: Configure your server to work with html5Mode -派对维基:
When you have html5Mode enabled, the #
character will no longer be used in your URLs. The #
symbol is useful because it requires no server side configuration. Without #
, the URL looks much nicer, but it also requires server side rewrites.
这里我只从维基上复制了三个例子,以防维基丢失。可以通过搜索关键字 "URL rewrite" 找到其他示例(例如 for Firebase)。
阿帕奇
<VirtualHost *:80>
ServerName my-app
DocumentRoot /path/to/app
<Directory /path/to/app>
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]
</Directory>
</VirtualHost>
Documentation for rewrite module
nginx
server {
server_name my-app;
root /path/to/app;
location / {
try_files $uri $uri/ /index.html;
}
}
IIS
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" 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>
我遇到了同样的问题。我的 Angular 应用程序是 运行 在 Windows 服务器上。
我通过在 root 目录中创建一个 web.config 文件解决了这个问题。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS" 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>
我是 Angular 的新手 2. 我已将我的单页应用程序存储在服务器中名为“myapp”的文件夹中。我已经将 base 中的 URL 更改为 http://example.com/myapp/`.
我的项目有两个页面。所以我实现了 Angular 2 路由。我将默认页面设置为登录。当我在浏览器中输入 http://example.com/myapp/
时,它会自动重定向到 http://example.com/myapp/login
。但是,如果刷新该页面,我会收到 404
错误,提示未找到 http://example.com/myapp/login
。
但是如果我 运行 我的项目使用精简版服务器,一切正常。在这种情况下,index.html 中的基数 URL 将是 "/"
。如何解决?
事实上,刷新应用程序时出现 404 错误是正常的,因为浏览器中的实际地址正在更新(并且没有 # / hashbang 方法)。默认情况下,HTML5 历史用于 Angular2 中的重用。
要修复 404 错误,您需要更新您的服务器,以便为您定义的每个路由路径提供 index.html
文件。
如果你想切换到HashBang方式,你需要使用这个配置:
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
import {MyApp} from './myapp';
bootstrap(MyApp, [
ROUTER_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
在这种情况下,当你刷新页面时,它会再次显示(但你的地址中会有一个#
)。
这个 link 也可以帮助您:
希望对你有帮助, 蒂埃里
对于使用 Angular 2 rc4 或更高版本的阅读本文的人来说,LocationStrategy 似乎已从路由器移至通用。您必须从那里导入它。
还要注意 'provide' 行周围的大括号。
main.ts
// Imports for loading & configuring the in-memory web api
import { XHRBackend } from '@angular/http';
// The usual bootstrapping imports
import { bootstrap } from '@angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '@angular/http';
import { AppComponent } from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { Location, LocationStrategy, HashLocationStrategy} from '@angular/common';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
HTTP_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
]);
更新Angular 2 最终 版本
在app.module.ts中:
添加导入:
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
并在 NgModule 提供者中添加:
{provide: LocationStrategy, useClass: HashLocationStrategy}
示例 (app.module.ts):
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent],
})
export class AppModule {}
备选
使用带有 {useHash: true} 参数的 RouterModule.forRoot。
示例:(来自 angular docs)
import { NgModule } from '@angular/core';
...
const routes: Routes = [//routes in here];
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(routes, { useHash: true })
],
bootstrap: [AppComponent]
})
export class AppModule { }
或许您可以在 root
注册 RouterModule
的同时完成此操作。您可以使用 属性 useHash:true
传递第二个对象,如下所示:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ROUTES } from './app.routes';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
RouterModule.forRoot(ROUTES ,{ useHash: true }),],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
如果您在 Visual Studio 2015 年 运行 Angular 2 到 ASP.NET 核心 1,您可能会发现 Jürgen Gutsch 的这个解决方案很有帮助。他在 a blog post 中描述了它。这对我来说是最好的解决方案。将下面提供的 C# 代码放在 Startup.cs public void Configure() 之前 app.UseStaticFiles();
app.Use( async ( context, next ) => {
await next();
if( context.Response.StatusCode == 404 && !Path.HasExtension( context.Request.Path.Value ) ) {
context.Request.Path = "/index.html";
await next();
}
});
对于真正想要 PathLocationStrategy
(即 html5Mode)而不是 HashLocationStrategy
的人(如我),请参阅第三方的 How to: Configure your server to work with html5Mode -派对维基:
When you have html5Mode enabled, the
#
character will no longer be used in your URLs. The#
symbol is useful because it requires no server side configuration. Without#
, the URL looks much nicer, but it also requires server side rewrites.
这里我只从维基上复制了三个例子,以防维基丢失。可以通过搜索关键字 "URL rewrite" 找到其他示例(例如
阿帕奇
<VirtualHost *:80>
ServerName my-app
DocumentRoot /path/to/app
<Directory /path/to/app>
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]
</Directory>
</VirtualHost>
Documentation for rewrite module
nginx
server {
server_name my-app;
root /path/to/app;
location / {
try_files $uri $uri/ /index.html;
}
}
IIS
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" 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>
我遇到了同样的问题。我的 Angular 应用程序是 运行 在 Windows 服务器上。
我通过在 root 目录中创建一个 web.config 文件解决了这个问题。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS" 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>