3

我正在使用 Angular SPA 项目模板为 dotnet core(VS2017 和 dotnet core 2.0 中可用的模板)开发一个项目。

如果用户访问无效的 URL,我有一个 Angular 组件来显示“未找到”消息。

我还启用了服务器端预渲染。从服务器返回预呈现的“未找到”页面时,如何让它返回 404 的 HTTP 状态代码?

我发现的每种方法都使用 Express 作为后端网络服务器,我无法在 aspnet 核心后端找到任何资源来执行此操作。

谢谢你的帮助!


为清楚起见进行编辑:

我不希望为特定的 MVC 控制器操作或应用程序错误返回 404。

我希望从特定的 Angular2/4 组件返回 404,由Microsoft.AspNetCore.SpaServices在服务器端呈现。

作为比较,这里是一个使用 NodeJS 上的 Express Web 服务器和 Angular Universal 进行服务器端渲染的解决方案示例。

4

1 回答 1

2

我找到了解决方案。

首先,我们需要创建一个组件可以用来设置状态码的可注入服务:

import { Injectable } from '@angular/core';

@Injectable()
export class HttpStatusCodeService {

  private statusCode: number;

  constructor(){
    this.statusCode = 200;
  }

  public setStatusCode(statusCode: number) {
    this.statusCode = statusCode;
  }

  public getStatusCode(): number {
    return this.statusCode;
  }
}

我们需要将此服务添加到providersAppModule模块中的数组中:

...
providers: [
    ...
    HttpStatusCodeService,
    ...
]
...

然后我们需要在我们的boot.server.ts文件中添加两行(加上 import 语句)(注意这是基于 VS2017 模板创建的 stock 文件):

import 'reflect-metadata';
import 'zone.js';
import 'rxjs/add/operator/first';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/core';
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
import { AppModule } from './app/app.module.server';

//ADD THIS LINE
import { HttpStatusCodeService } from './path/to/services/http-status-code.service';

enableProdMode();

export default createServerRenderer(params => {
    const providers = [
        { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
        { provide: APP_BASE_HREF, useValue: params.baseUrl },
        { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
    ];

    return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
        const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
        const state = moduleRef.injector.get(PlatformState);
        const zone = moduleRef.injector.get(NgZone);

        //ADD THIS LINE: this will get the instance of the HttpStatusCodeService created for this request.
        const statusCodeService = moduleRef.injector.get(HttpStatusCodeService); 

        return new Promise<RenderResult>((resolve, reject) => {
            zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
            appRef.isStable.first(isStable => isStable).subscribe(() => {
                // Because 'onStable' fires before 'onError', we have to delay slightly before
                // completing the request in case there's an error to report
                setImmediate(() => {
                    resolve({
                        html: state.renderToString(),

                        //ADD THIS LINE: this will get the currently set status code and return it along with the prerendered html string
                        statusCode: statusCodeService.getStatusCode() 
                    });
                    moduleRef.destroy();
                });
            });
        });
    });
});

最后,我们需要在任何不应返回 HTTP 200 的组件中设置状态码:

import { Component } from '@angular/core';

import { HttpStatusCodeService } from './path/to/services/http-status-code.service';

@Component({
    selector: 'not-found',
    templateUrl: './not-found.html'
})
export class NotFoundComponent {

  constructor(private httpStatusCodeService: HttpStatusCodeService) {
    httpStatusCodeService.setStatusCode(404);
  }
}
于 2017-10-17T12:56:12.363 回答