刷新页面导致 404 错误 - Angular 6
refreshing the page results in 404 error- Angular 6
我正在 Angular6 的帮助下构建一个应用程序并面临路由问题。当我单击特定选项卡时,所有 路由 都在工作,但每当我 刷新 当前页面时,它都会抛出 404错误。我在 Stack overflow 上看到过很多关于这个问题的帖子,但都没有解决这个问题。
下面是我的app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from './app.component';
import {FetchApiComponent} from './fetch-api/fetch-api.component';
import {FormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import {UserServiceLatest} from './fetch-latest/app.service';
import {UserServiceTop} from './fetch-top/app.service';
import {YoutubePlayerModule} from 'ngx-youtube-player';
import {SidebarComponent} from './sidebar/sidebar.component';
import {FetchLatestComponent} from './fetch-latest/fetch-latest.component';
import { FetchTopComponent } from './fetch-top/fetch-top.component'
import {UserService} from './fetch-api/app.service';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AngularFireModule } from 'angularfire2';
import * as firebase from 'firebase';
import { firebaseConfig } from './../environments/firebase.config';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import {PushService} from './push.service';
const appRoutes: Routes = [
{
path: '',
component: FetchApiComponent
},
{
path: '/latest',
component: FetchLatestComponent
},
{
path: '/top',
component: FetchTopComponent
},
{
path :'*',
component: FetchApiComponent
}
];
firebase.initializeApp(firebaseConfig);
@NgModule({
declarations: [
AppComponent,
FetchApiComponent,SidebarComponent, FetchLatestComponent, FetchTopComponent
],
imports: [
RouterModule.forRoot(appRoutes),
BrowserModule, YoutubePlayerModule,
FormsModule,
AngularFireModule.initializeApp(firebaseConfig),
AngularFireDatabaseModule,environment.production ?ServiceWorkerModule.register('firebase-messaging-sw.js'):[],ServiceWorkerModule.register('/firebase-messaging-sw.js', { enabled: environment.production }),
HttpClientModule,environment.production ? ServiceWorkerModule.register('ngsw-worker.js') : [], ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
],
providers: [UserService,UserServiceTop,UserServiceLatest,PushService],
bootstrap: [AppComponent]
})
export class AppModule {}
你能给我指明正确的方向吗?
您将在您的示例中看到 url,一旦您收到 404 错误,您将无法使其正常工作,但是如果您 在 angular-特定的 url 喜欢 /#latest
它会起作用。
为什么刷新时停止工作?您的 网络服务器正在拦截来自浏览器的 GET 请求,并试图直接进入不存在的目录 /latest
。它不知道它需要去 /bosv2
,找到一个 angular 应用程序,然后将小结束位添加到您的路径,这是一个非真实的目录,但是 [=55] 的路由=].在您的本地,它会像您执行 ng serve 时一样工作,webpack 网络服务器为此做好了准备,但您托管应用程序的主机却没有。
默认情况下,angular 使用 HTML5 风格的导航,但根据您当前的网络服务器设置,您将需要旧的 angularjs样式(带哈希#)。
从这里开始,您有两个解决方案:
- 更改您的网络服务器配置
告诉 Angular 使用 HashLocationStrategy(完全有效的解决方案),您可以通过在对象中提供 useHash: true
作为 HashLocationStrategy 的第二个参数来使用 HashLocationStrategy AppModule 中的 RouterModule.forRoot。
@NgModule({
进口:[
...
RouterModule.forRoot(routes, { useHash: true }) // .../#/latest/
],
...
我想说采用散列样式有几个缺点,这可能与您的情况无关:
- 它不会生成更易于用户理解和记忆的干净且 SEO 友好的 URL。
- 您无法利用服务器端呈现。
希望此回答对您有所帮助:)
要避免使用散列路由,您必须正确编辑您的网络服务器配置,这是最好的解决方案。您只需对其进行配置,使其回退到 index.html
,即 Angular 的 bootstrap。虽然没有通用的配置,但这里有一些:
Apache
向 .htaccess
文件添加重写规则
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
Nginx
在您的位置块中使用 try_files
try_files $uri $uri/ /index.html;
IIS
将重写规则添加到 web.config
<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="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
GitHub 页数
不能直接配置,但是可以添加404页面。将 index.html
复制到同一目录中的 404.html
或添加符号链接:ln -s index.html 404.html
.
Firebase 托管
添加重写规则。
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
使用 .htaccess 您也可以尝试以下方式:
<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 会像:
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
重写规则 ^/(.*)$ /index.html [L]
在app.module.ts
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
导入后向提供程序添加以下行。
{provide: LocationStrategy, useClass: HashLocationStrategy}
例如:
providers: [AuthService,
AuthGuard,
FlxUiDataTable,
{provide: LocationStrategy, useClass: HashLocationStrategy}]
这将解决您的问题。阅读 Documentation 此处。
就我而言,我做了以下事情
方法一:
在你的 app.module.ts 中导入下面的东西
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
@NgModule({
declarations: [...],
imports: [...],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent]
})
并使用
构建
ng build --base-href /[PROJECT_NAME]/
方法二:
对于 nginx,
nano /etc/nginx/sites-available/default
在位置块中添加以下行
location /[PROJECT_NAME] {
try_files $uri $uri/ /[PROJECT_NAME]/index.html;
}
sudo service nginx restart
并使用
构建
ng build --base-href /[PROJECT_NAME]/
将 .htaccess
文件添加到您的 src
文件夹。
.htaccess 文件
<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>
通过将 .htaccess
文件添加到 angular.json
中的 assets
,将其加载到构建目录 dist
中
"assets": [
"src/favicon.ico",
"src/assets",
"src/.htaccess"
],
在同一 URL 导航上重新获取数据
imports: [RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload' })],
从 Apache 2.4 开始,您可以使用 FallbackResource 指令而不是重写,因此它看起来像:
FallbackResource /index.html
如果您有不同的基本 href(例如 /awesomeapp),请将其更改为:
<Location /awesomeapp>
FallbackResource /awesomeapp/index.html
</Location>
如果您使用的是 cpanel,那么很容易解决这个问题。
转到高级选项
Step 1: Go to Error Pages.
Step 2: Copy your index.html code and paste it in 404.shtml.
That's it technically all your routes are redirected to index.html file. That's what angular wants :) and everything will work normal.
这里有一些参考链接
我正在 Angular6 的帮助下构建一个应用程序并面临路由问题。当我单击特定选项卡时,所有 路由 都在工作,但每当我 刷新 当前页面时,它都会抛出 404错误。我在 Stack overflow 上看到过很多关于这个问题的帖子,但都没有解决这个问题。
下面是我的app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from './app.component';
import {FetchApiComponent} from './fetch-api/fetch-api.component';
import {FormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import {UserServiceLatest} from './fetch-latest/app.service';
import {UserServiceTop} from './fetch-top/app.service';
import {YoutubePlayerModule} from 'ngx-youtube-player';
import {SidebarComponent} from './sidebar/sidebar.component';
import {FetchLatestComponent} from './fetch-latest/fetch-latest.component';
import { FetchTopComponent } from './fetch-top/fetch-top.component'
import {UserService} from './fetch-api/app.service';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AngularFireModule } from 'angularfire2';
import * as firebase from 'firebase';
import { firebaseConfig } from './../environments/firebase.config';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import {PushService} from './push.service';
const appRoutes: Routes = [
{
path: '',
component: FetchApiComponent
},
{
path: '/latest',
component: FetchLatestComponent
},
{
path: '/top',
component: FetchTopComponent
},
{
path :'*',
component: FetchApiComponent
}
];
firebase.initializeApp(firebaseConfig);
@NgModule({
declarations: [
AppComponent,
FetchApiComponent,SidebarComponent, FetchLatestComponent, FetchTopComponent
],
imports: [
RouterModule.forRoot(appRoutes),
BrowserModule, YoutubePlayerModule,
FormsModule,
AngularFireModule.initializeApp(firebaseConfig),
AngularFireDatabaseModule,environment.production ?ServiceWorkerModule.register('firebase-messaging-sw.js'):[],ServiceWorkerModule.register('/firebase-messaging-sw.js', { enabled: environment.production }),
HttpClientModule,environment.production ? ServiceWorkerModule.register('ngsw-worker.js') : [], ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
],
providers: [UserService,UserServiceTop,UserServiceLatest,PushService],
bootstrap: [AppComponent]
})
export class AppModule {}
你能给我指明正确的方向吗?
您将在您的示例中看到 url,一旦您收到 404 错误,您将无法使其正常工作,但是如果您 在 angular-特定的 url 喜欢 /#latest
它会起作用。
为什么刷新时停止工作?您的 网络服务器正在拦截来自浏览器的 GET 请求,并试图直接进入不存在的目录 /latest
。它不知道它需要去 /bosv2
,找到一个 angular 应用程序,然后将小结束位添加到您的路径,这是一个非真实的目录,但是 [=55] 的路由=].在您的本地,它会像您执行 ng serve 时一样工作,webpack 网络服务器为此做好了准备,但您托管应用程序的主机却没有。
默认情况下,angular 使用 HTML5 风格的导航,但根据您当前的网络服务器设置,您将需要旧的 angularjs样式(带哈希#)。
从这里开始,您有两个解决方案:
- 更改您的网络服务器配置
告诉 Angular 使用 HashLocationStrategy(完全有效的解决方案),您可以通过在对象中提供
useHash: true
作为 HashLocationStrategy 的第二个参数来使用 HashLocationStrategy AppModule 中的 RouterModule.forRoot。@NgModule({ 进口:[ ... RouterModule.forRoot(routes, { useHash: true }) // .../#/latest/ ], ...
我想说采用散列样式有几个缺点,这可能与您的情况无关:
- 它不会生成更易于用户理解和记忆的干净且 SEO 友好的 URL。
- 您无法利用服务器端呈现。
希望此回答对您有所帮助:)
要避免使用散列路由,您必须正确编辑您的网络服务器配置,这是最好的解决方案。您只需对其进行配置,使其回退到 index.html
,即 Angular 的 bootstrap。虽然没有通用的配置,但这里有一些:
Apache
向 .htaccess
文件添加重写规则
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
Nginx
在您的位置块中使用 try_files
try_files $uri $uri/ /index.html;
IIS
将重写规则添加到 web.config
<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="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
GitHub 页数
不能直接配置,但是可以添加404页面。将 index.html
复制到同一目录中的 404.html
或添加符号链接:ln -s index.html 404.html
.
Firebase 托管
添加重写规则。
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
使用 .htaccess 您也可以尝试以下方式:
<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 会像:
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
重写规则 ^/(.*)$ /index.html [L]
在app.module.ts
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
导入后向提供程序添加以下行。
{provide: LocationStrategy, useClass: HashLocationStrategy}
例如:
providers: [AuthService,
AuthGuard,
FlxUiDataTable,
{provide: LocationStrategy, useClass: HashLocationStrategy}]
这将解决您的问题。阅读 Documentation 此处。
就我而言,我做了以下事情
方法一:
在你的 app.module.ts 中导入下面的东西
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
@NgModule({
declarations: [...],
imports: [...],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}],
bootstrap: [AppComponent]
})
并使用
构建ng build --base-href /[PROJECT_NAME]/
方法二:
对于 nginx,
nano /etc/nginx/sites-available/default
在位置块中添加以下行
location /[PROJECT_NAME] {
try_files $uri $uri/ /[PROJECT_NAME]/index.html;
}
sudo service nginx restart
并使用
构建ng build --base-href /[PROJECT_NAME]/
将 .htaccess
文件添加到您的 src
文件夹。
.htaccess 文件
<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>
通过将 .htaccess
文件添加到 angular.json
assets
,将其加载到构建目录 dist
中
"assets": [
"src/favicon.ico",
"src/assets",
"src/.htaccess"
],
在同一 URL 导航上重新获取数据
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
从 Apache 2.4 开始,您可以使用 FallbackResource 指令而不是重写,因此它看起来像:
FallbackResource /index.html
如果您有不同的基本 href(例如 /awesomeapp),请将其更改为:
<Location /awesomeapp>
FallbackResource /awesomeapp/index.html
</Location>
如果您使用的是 cpanel,那么很容易解决这个问题。
转到高级选项
Step 1: Go to Error Pages.
Step 2: Copy your index.html code and paste it in 404.shtml.
That's it technically all your routes are redirected to index.html file. That's what angular wants :) and everything will work normal.
这里有一些参考链接