【问题标题】:refreshing the page results in 404 error- Angular 6刷新页面导致 404 错误-Angular 6
【发布时间】:2018-11-27 04:44:21
【问题描述】:

我正在 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 {}

你能指出我正确的方向吗?

【问题讨论】:

  • 如果您手动转到根路径,是否正确加载了 FetchApiComponent?是不是只有刷新的时候才会出现?
  • 只有在我刷新页面时才会发生。例如:我的 URL 是:http://localhost:4200/,页面上有导航链接,Fetch 就是其中之一,当我点击 Fetch 栏时,它会将 URL 设为:http://localhost:4200/fetch,它工作正常,但是当我刷新此页面时,它会向我抛出错误。
  • 我不明白您第一次访问localhost:4200 时是如何工作的,因为它与您刷新页面一样......当您刷新时,尝试访问哪个 url?您是否在路由器的 javascript 控制台中收到错误?
  • 好的,我明白了,这是由于你的网络服务器造成的,给我两分钟,我可以给你一个如何解决这个问题的例子

标签: angular6


【解决方案1】:

为避免使用散列路由,您必须正确编辑您的网络服务器配置,这是最佳解决方案。您只需对其进行配置,使其回退到 index.html,这是 Angular 的引导程序。虽然没有通用的配置,但这里有一些:

阿帕奇

.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"
} ]

来源:https://angular.io/guide/deployment#server-configuration

【讨论】:

  • 效果很好!谢谢 :) (使用 Angular 7)
  • 知道如何在 JBOSS 服务器上进行设置吗?
  • 我不太熟悉 JBOSS,但试试这个:&lt;error-page&gt;&lt;location&gt;/index.html&lt;/location&gt;&lt;/error-page&gt; 它应该将错误页面重定向到 Angular 端点 (index.html)
【解决方案2】:

如果您使用的是 cpanel,那么这个问题很容易解决。

转到高级选项

第 1 步:转到错误页面。

第 2 步:复制您的 index.html 代码并将其粘贴到 404.shtml 中。

从技术上讲,您的所有路由都将重定向到 index.html 文件。这就是 Angular 想要的 :) 一切都会正常工作。

这里有一些参考链接

Namecheap Error Page Config

Godaddy Error Page config

【讨论】:

  • 这是一个很好的“后备”选项。但是在 404 的情况下,它不会加载相同的页面/路由,而是默认路由。
【解决方案3】:

从 Apache 2.4 开始,您可以使用 FallbackResource 指令而不是重写,所以它看起来像:

FallbackResource /index.html

如果您有不同的基本 href(例如 /awesomeapp),请将其更改为:

<Location /awesomeapp>
    FallbackResource /awesomeapp/index.html
</Location>

【讨论】:

  • 但非常简单且有效的解决方案
【解决方案4】:

在相同的 URL 导航上重新获取数据

进口:[RouterModule.forRoot(路线,{ onSameUrlNavigation: '重新加载' })],

【讨论】:

    【解决方案5】:

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

    通过将assets 添加到angular.json 中的assets,将.htaccess 文件加载到您的构建目录dist

    "assets": [
         "src/favicon.ico",
         "src/assets",
         "src/.htaccess"
    ],
    

    【讨论】:

    • 一次性完成,谢谢!
    • 你好,它在 bigrock 服务器上工作,但它在 AWS 服务器上不工作为什么会发生有人知道吗??
    【解决方案6】:

    就我而言,我做了以下事情

    方法一:

    在你的 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 服务 nginx 重启

    并用

    构建

    ng build --base-href /[PROJECT_NAME]/

    【讨论】:

      【解决方案7】:

      在 app.module.ts 中

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

      导入后向提供者添加以下行。

      {provide: LocationStrategy, useClass: HashLocationStrategy}
      

      例如:

      providers: [AuthService, 
                  AuthGuard, 
                  FlxUiDataTable,
                  {provide: LocationStrategy, useClass: HashLocationStrategy}]
      

      这将解决您的问题。在此处阅读Documentation

      【讨论】:

        【解决方案8】:

        我认为您收到 404 是因为您请求的 http://localhost/route 在 tomcat 服务器上不存在。由于 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 Rewrite 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]

        【讨论】:

          【解决方案9】:

          使用 .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>
          

          【讨论】:

          • 真正的英雄!谢谢你。
          • 这似乎工作,虽然在刷新我得到新的这些错误 runtime.26209474bfa8dc87a77c.js:1 Uncaught SyntaxError: Unexpected token
          • @user3530687 - 这已经在答案中了 - 简而言之,该控件分配给 index.html 文件,而不是找到一些像通过的文件。
          • 很多人忘记添加RewriteRule ^ - [L],完全看答案,不要只复制最后一部分
          • 现实生活中的英雄!
          【解决方案10】:

          您将在示例 url 中看到,一旦出现 404 错误,您将无法使其正常工作,但如果您之前包含一个哈希 特定于角度的 url,例如 /#latest 它会工作的。

          为什么刷新时停止工作?您的网络服务器正在拦截来自浏览器的 GET 请求,并试图直接转到不存在的目录 /latest。它不知道它需要去/bosv2,找到一个角度应用程序,然后将小结尾位添加到您的路径中,该路径不是真实的目录,而是角度的路由。在您的本地,它会像您执行 ng serve 一样工作,webpack webserver 已为此做好准备,但不是您托管应用程序的主机。

          默认情况下,Angular 使用 HTML5 样式导航,但根据您当前的网络服务器设置,您将需要旧的 angularjs 样式(带有 hash#)。

          从这里,您有两种解决方案

          1. 更改您的网络服务器配置
          2. 告诉 Angular 使用 HashLocationStrategy(完全有效的解决方案),您可以通过在对象中提供 useHash: true 作为 AppModule 中 RouterModule.forRoot 的第二个参数来使用 HashLocationStrategy。

            @NgModule({ 进口:[ ... RouterModule.forRoot(routes, { useHash: true }) // .../#/latest/ ], ...

          我会说散列样式有几个缺点,这可能与您的场景无关:

          1. 它不会生成更易于用户理解和记忆的干净且对 SEO 友好的 URL。
          2. 您无法利用服务器端呈现。

          希望这个答案对您有所帮助:)

          【讨论】:

          • 如何在 Angular 6 中使用 useHash:true
          • 其实是angular6:official docs
          • 谢谢!请问在 URL 中使用 hash 标记是否有任何缺点或者使用起来完全安全?
          • 好的..谢谢你:)
          • @JavierAviles 如何更改网络服务器配置?我目前在 IIS 上托管我的网站,我不想使用散列