Angular 2路由在部署到Http服务器时无法正常工作

66
我将开发一个简单的Angular 2应用程序。 我使用Angular CLI创建了一个带有路由的项目,并使用“ng generate component”命令向应用程序添加了几个组件。 然后我在“app-routing.module.ts”中指定了路由,如下所示。
导入: import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { AboutComponent } from './about/about.component'; import { UserComponent } from './user/user.component'; import { ErrorComponent } from './error/error.component'; import { SpecialpageComponent } from './specialpage/specialpage.component';
路由: const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'about', component: AboutComponent }, { path: 'user', component: UserComponent }, { path: 'specialpage', component: SpecialpageComponent }, { path: '**', component: ErrorComponent }
];
@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: [] }) export class AppRoutingModule { }
“app.module.ts”如下所示。
从'@angular/platform-browser'导入BrowserModule;
从'@angular/core'导入NgModule;
从'@angular/forms'导入FormsModule;
从'@angular/http'导入HttpModule;
从'./app-routing.module'导入AppRoutingModule;
从'./app.component'导入AppComponent; 从'./home/home.component'导入HomeComponent; 从'./about/about.component'导入AboutComponent; 从'./error/error.component'导入ErrorComponent; 从'./user/user.component'导入UserComponent; 从'./specialpage/specialpage.component'导入SpecialpageComponent;
@NgModule({ declarations: [ AppComponent, HomeComponent, AboutComponent, ErrorComponent, UserComponent, SpecialpageComponent ], imports: [ BrowserModule, FormsModule, HttpModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) 导出类AppModule { }

我没有对其他组件进行任何修改。 然后,我使用'ng serve'命令部署了应用程序,并且应用程序与链接一起正常工作。 例如:http://localhost:4200/about

enter image description here

但是当我在http-server中部署项目时,链接并没有按照预期工作。我使用了“http-server ./dist”命令部署应用程序,并成功部署了应用程序,但链接无法正常工作。当我访问“http://localhost:4200/about”时,它会出现404错误。

enter image description here

我做错了什么吗?为什么 'ng-serve' 能用,而 'http-server' 不能用?

非常感谢您的帮助。

我已将我的项目上传到 github


6
尝试使用 imports: [RouterModule.forRoot(routes, {useHash: true})],。如果它可以这样工作,那么你需要在生产服务器上启用HTML5 pushState。 - Günter Zöchbauer
还可以尝试将 path: '' 的路由添加 pathMatch: 'full' - Günter Zöchbauer
1
是的,请不要使用 useHash:true :D。正如我在最初的评论中所说,您必须配置服务器以支持HTML5 pushState。useHash:true 只是为了调试问题的原因。 - Günter Zöchbauer
1
@GünterZöchbauer,非常感谢您提供的有关此事的宝贵信息。我会尝试寻找解决方案。再次感谢您。 - kinath_ru
2
你找到解决方案了吗?我也遇到了同样的问题。 - Ziggler
显示剩余8条评论
19个回答

53

通过实现 HashLocationStrategy 解决了这个问题,它会为所有路由添加 #。您只需将 HashLocationStrategy 添加到 AppModuleproviders 中即可实现此功能。

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

并添加相应的导入

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

这将解决你的问题。

如果你不想使用 HashLocationStrategy,你可以使用 PathLocationStrategy,这样你的 Angular 应用程序在 URL 中将不会显示 Hash 符号。


1
我有同样的问题,而且我在我的app.modules.ts中也有这个问题。我没有收到任何404错误。在应用程序组件初始化方法之后,好像我的路由不起作用,什么都没有加载。ng serve可以正常工作,但我的本地主机不行。 - Ziggler
谢谢!帮了我大忙。但是在部署的网站URL中始终显示井号符号是否可以?嗯 - ninjaxelite
2
我觉得这不应该成为一个问题。请修复此问题,Google。改变整个互联网的结构来取悦我。 - Kyle Vassella
我尝试了各种方法来让它在我的 nginx 和 IIS 上运行,但都无济于事。直到我找到了这个。难道我们不希望 Angular 默认使用 HashLocationStrategy 吗?甚至更进一步,根本就不应该有不使用它的选项吧? - Ya.
谢谢,这解决了我的问题。 - ismail baig
显示剩余4条评论

24

这是因为http-server不支持像lite-server或webpack-dev server那样的回退。这就是为什么它显示404未找到

有两种解决此问题的方法:

  1. 您可以使用如上所述的HashLocationStrategy
  2. 如果您将其部署到Apache或IIS服务器,则可以添加如此处所述的配置!

注意:对于开发,您可以使用lite-server。

希望这能帮到您。


14

我通过在AppModule提供者中添加以下内容解决了这个问题:

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

导入

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

接下来我创建了 .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

没有#符号的URL很好用 :)


我该在哪里添加 .htaccess 文件? - jay khatri
1
@jaykhatri 在您的 Web 服务器上的主目录中(即 Angular 应用程序所在的位置)。它可能是 public_html。 - Maciej Socha

10

这样问题就会得到解决:

情况1: Angular版本低于5.1

1)像下面提到的那样使用HashLocationStrategy

AppModule中执行以下步骤。

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

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

情况2: Angular版本等于或高于5.1

2.1)Angular为了克服服务器上的刷新问题,引入了onSameUrlNavigation属性。

2.2)将onSameUrlNavigation添加到导入数组中的RouterModule.forRoot中。

a)在应用程序的主路由模块(即app.routing.module.ts / app.routing.ts)中添加该属性。

请参见下面的示例:

@ngModule({

    imports: 
    [
       RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})
    ],

    exports: [RouterModule],
 });

希望它能帮助到某人。


6

这种情况会发生是因为它去查找一个页面关于,但实际上根本不存在,因此出现404错误。可能的解决方法:

  1. If you want to go with http-server then use a proxy which will redirect everything to http://localhost:your-port.

    Option: -P or --proxy Proxies all requests which can't be resolved locally to the given url. e.g.: -P http://someurl.com

  2. Don't use express at all. Create your own http-server using express & Redirect everything to index.html

    Assuming public is your folder where u keep all transpiled things.

    var express = require('express');
    var app = express();
    
    var path = __dirname + '/public';
    var port = 8080;
    
    app.use(express.static(path));
    app.get('*', function(req, res) {
        res.sendFile(path + '/index.html');
    });
    app.listen(port);
    

非常抱歉,我没有完全理解你的意思。我对Angular还是个新手,这里并没有进行任何复杂的操作。关于你提到的第一个选项,我尝试了托管我的服务器,并且在没有端口的情况下访问了URL。只有根URL可以正常工作,无法进入其他链接。 - kinath_ru
http-server --port 4200 -P http://someurl.com 在我的情况下引发了一个无限循环。 - user1767316

5

3

对于Apache服务器:

在生产服务器中

在项目根目录下添加或创建".htaccess"文件,并像以下示例一样向.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

3

我也遇到了这个问题,并找到了一种不需要HashLocationStrategy解决方案的解决方法。

问题是,像Tomcat这样的服务器会查找实际文件夹(例如:/about),但在Angular应用程序中不存在,因为它是单页应用程序。 因此,每个请求都需要重定向到index.html。

解决此问题最简单的方法是添加以下Java类并像下面这样覆盖addResourceHandlers()方法:

@Configuration
class WebMVCCustomConfiguration implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:static").resourceChain(true)
            .addResolver(new PathResourceResolver() {
                @Override
                protected Resource getResource(String resourcePath, Resource location) {
                    String path = "static/";
                    path += (resourcePath.contains(".") && !resourcePath.equals("index.html")) ? resourcePath : "index.html";

                    Resource resource = new ClassPathResource(path);
                    return resource.exists() ? resource : null;
                }
            });
    }
  }

这将解决所有问题,这个解决方案在任何地方都不存在。

很高兴知道有这样的解决方案,但我认为最好使用Angular提供的机制,比如上面提到的HashLocationStrategy。干杯 :) - TRUSTMEIMJEDI

2
根据https://angular.io/guide/deployment的文档(Apache,你也可以寻找nginx),您需要使用.htaccess文件将服务器指向index.html。
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

1
你应该尝试在应用程序初始化的时候指定构建的URL:
Ng build --prod --base-href="http://your.url.com/subdirectory/etc"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接