本文介绍了ASP.Net Core 2.1 Angular SSR/Universal 返回 Http 状态码 404的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有了 SpaPrerenderingExtensions 在 ASP.Net core 2.0 JavaScriptServices 中可用,我们似乎可以从 SpaPrerenderingExtensions 的 Angular (SSR) 应用程序返回 HTTP 状态代码 将用于将 HTTP 状态代码返回给客户端.

如果你看一下SpaPrerenderingExtensions

中的以下方法

private static async Task ServePrerenderResult(HttpContext context, RenderToStringResult renderResult)

SpaPrerenderingExtensions 的完整代码可在此处获得:https://github.com/aspnet/JavaScriptServices/blob/8ded472fe93123079ab97c9332f24460340876d2/src/Microsoft.AspNetCore.SpaServices.Extensions/Sparenders.Extensions/Sparenders.>

您会注意到 renderResult.Html 包含从 Angular Server App 返回的 html 标记,而 renderResult.StatusCode.Value 包含状态代码.

启用 SSR 的官方文档(可在 https://docs.microsoft.com/en-us/aspnet/core/spa/angular?view=aspnetcore-2.1&tabs=visual-studio#服务器端渲染) 建议将以下代码添加到 main.server.ts 文件中.

import 'zone.js/dist/zone-node';导入反射元数据";从'@angular/platform-server'导入{renderModule,renderModuleFactory};从'@angular/common'导入{APP_BASE_HREF};从@angular/core"导入 { enableProdMode };从'@nguniversal/module-map-ngfactory-loader'导入{提供模块映射};从'aspnet-prerendering'导入{createServerRenderer};从'./app/app.server.module'导出{ AppServerModule};enableProdMode();导出默认 createServerRenderer(params => {const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;常量选项 = {文件:params.data.originalHtml,网址:params.url,额外提供者:[提供模块映射(LAZY_MODULE_MAP),{ 提供:APP_BASE_HREF,useValue:params.baseUrl },{ 提供:'BASE_URL',useValue:params.origin + params.baseUrl }]};const renderPromise = AppServerModuleNgFactory?/* AoT */renderModuleFactory(AppServerModuleNgFactory, options):/* dev */renderModule(AppServerModule, options);返回 renderPromise.then(html => ({ html }));});

谁能指导我如何从 Angular 服务器应用程序返回状态代码,以便 ASP.Net Core 2.0 SpaPrerenderingExtensions 正确选择它.

任何帮助将不胜感激.例如,如果我有一个具有状态代码值的服务,我如何从该服务中选择值并传递到 main.server.ts 文件中的服务器.

注意:我使用的是基于 ASP.Net Core 2.1 Angular CLI 6 的模板.

解决方案

我将此作为答案发布,因为我可以比评论更好地格式化内容,但是这都是未经测试的,并且基于查看我的过时解决方案,您的上面的代码片段和 Angular6 文档(我没有最新的 VS 模板,所以我现在无法测试).

提供给 renderModule() 的 options 参数对象renderModuleFactory() 有一个 extraProviders我相信,它可以让我们向 AppServerModule 模块添加额外的提供程序.

这是我的想法:

  • 使用我的 HttpStatusCodeService 来自我的回答:aspnet 核心 SPA Angular 应用程序返回 404 状态码
  • 将其添加到 AppBrowserModule 模块中的 providers 数组(仅浏览器模块,而不是服务器模块).
    • 这将允许应用在浏览器中运行时正常注入服务.
  • main.server.ts 文件中实例化 HttpStatusCodeService 并将该实例作为提供程序添加到 extraProviders 数组中.
    • 这将允许在应用程序在服务器上运行时注入服务,同时还为我们提供对注入服务的引用.
  • 使用对服务的引用来确定响应是否需要为 404.

这是我未经测试尝试修改您的 main.server.ts 文件片段以使其工作.

import 'zone.js/dist/zone-node';导入反射元数据";从'@angular/platform-server'导入{renderModule,renderModuleFactory};从'@angular/common'导入{APP_BASE_HREF};从@angular/core"导入 { enableProdMode };从'@nguniversal/module-map-ngfactory-loader'导入{提供模块映射};从'aspnet-prerendering'导入{createServerRenderer};从 './app/app.module.server' 导出 { AppServerModule };//添加这一行从'./path/to/services/http-status-code.service'导入{HttpStatusCodeService};enableProdMode();导出默认 createServerRenderer(params => {const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;//添加此行 - 我们手动实例化服务,因此我们有对它的引用.让 statusCodeService = new HttpStatusCodeService();常量选项 = {文件:params.data.originalHtml,网址:params.url,额外提供者:[提供模块映射(LAZY_MODULE_MAP),{ 提供:APP_BASE_HREF,useValue:params.baseUrl },{ 提供:'BASE_URL',useValue:params.origin + params.baseUrl },//添加此行 - 我们为使用我们的实例的服务添加了一个提供者.{ 提供:HttpStatusCodeService,useValue:statusCodeService },]};const renderPromise = AppServerModuleNgFactory?/* AoT */renderModuleFactory(AppServerModuleNgFactory, options):/* dev */renderModule(AppServerModule, options);返回 renderPromise.then((html) => {//添加此行 - 从服务中获取状态代码.让 statusCode: number = statusCodeService.getStatusCode();返回 {html: statusCode == 404 ?'找不到网页!':html,状态码:状态码}});});

在我的原始解决方案中,我使用 Angular 组件呈现了我的 404 Not Found 页面,因此我不会覆盖返回的 HTML (html: html, statusCode: statusCode).

为了完整起见,这里是上面链接的答案中的 HttpStatusCodeService:

import { Injectable } from '@angular/core';@Injectable()导出类 HttpStatusCodeService {私人状态代码:号码;构造函数(){this.statusCode = 200;}公共 setStatusCode(statusCode: number) {this.statusCode = statusCode;}公共 getStatusCode(): number {返回 this.statusCode;}}

让我知道这是否有效.如果没有,我可以尝试设置一个测试环境来进一步研究这个问题,但没有承诺.

With SpaPrerenderingExtensions available in ASP.Net core 2.0 JavaScriptServices, it seems that we can return the HTTP Status Code from the Angular (SSR) App which SpaPrerenderingExtensions will use to return the HTTP Status Code to the client.

If you take a look at below method in SpaPrerenderingExtensions

private static async Task ServePrerenderResult(HttpContext context, RenderToStringResult renderResult)

Complete code of SpaPrerenderingExtensions is available here: https://github.com/aspnet/JavaScriptServices/blob/8ded472fe93123079ab97c9332f24460340876d2/src/Microsoft.AspNetCore.SpaServices.Extensions/Prerendering/SpaPrerenderingExtensions.cs

You will notice that renderResult.Html contains the html markup returned from Angular Server App whereas renderResult.StatusCode.Value contains the status code.

The official documentation for enabling SSR (available at https://docs.microsoft.com/en-us/aspnet/core/spa/angular?view=aspnetcore-2.1&tabs=visual-studio#server-side-rendering) suggest adding below code to the main.server.ts file.

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModule, renderModuleFactory } from '@angular/platform-server';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { createServerRenderer } from 'aspnet-prerendering';
export { AppServerModule } from './app/app.server.module';

enableProdMode();

export default createServerRenderer(params => {
  const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;

  const options = {
    document: params.data.originalHtml,
    url: params.url,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP),
      { provide: APP_BASE_HREF, useValue: params.baseUrl },
      { provide: 'BASE_URL', useValue: params.origin + params.baseUrl }
    ]
  };

  const renderPromise = AppServerModuleNgFactory
    ? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
    : /* dev */ renderModule(AppServerModule, options);

  return renderPromise.then(html => ({ html }));
});

Can anyone please guide how do I return the status code from the Angular Server App so that its properly picked up by the ASP.Net Core 2.0 SpaPrerenderingExtensions.

Any help would be highly appreciated. For example if I have a service which has value of status code, how do I pick value from that service and pass to server in main.server.ts file.

Note: I am using ASP.Net Core 2.1 Angular CLI 6 based template.

解决方案

I am posting this as an answer because I can format things better than in a comment, however this is all untested and based of looking at my outdated solution, your code snippets above, and the Angular6 docs (I don't have the latest VS templates so I can't test at the moment).

The options parameter object that is given to both renderModule() and renderModuleFactory() has an extraProviders array that, I believe, will let us add additional providers to the AppServerModule module.

Here is my idea:

  • Use my HttpStatusCodeService from my answer here: Return 404 status code in aspnet core SPA Angular application
  • Add it to the providers array in the AppBrowserModule module (only the browser module, not the server module).
    • This will allow the service to be injected normally while the app is running in the browser.
  • Instantiate HttpStatusCodeService in main.server.ts file and add that instance as a provider in the extraProviders array.
    • This will allow the service to be injected while the app is running on the server while also giving us a reference to the injected service.
  • Use the reference to the service to determine if the response needs to be a 404.

Here is my untested attempt to modify your main.server.ts file snippet to work.

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModule, renderModuleFactory } from '@angular/platform-server';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { createServerRenderer } from 'aspnet-prerendering';
export { AppServerModule } from './app/app.module.server';

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

enableProdMode();

export default createServerRenderer(params => {
  const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;

  //ADD THIS LINE - We manually instantiate the service so we have a reference to it.
  let statusCodeService = new HttpStatusCodeService();

  const options = {
    document: params.data.originalHtml,
    url: params.url,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP),
      { provide: APP_BASE_HREF, useValue: params.baseUrl },
      { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },

      //ADD THIS LINE - We add a provider for the service that uses our instance.
      { provide: HttpStatusCodeService, useValue: statusCodeService },
    ]
  };

  const renderPromise = AppServerModuleNgFactory
    ? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
    : /* dev */ renderModule(AppServerModule, options);

  return renderPromise.then((html) => {

    //ADD THIS LINE - get the status code from the service.
    let statusCode: number = statusCodeService.getStatusCode();

    return {
      html: statusCode == 404 ? 'Page not found!' : html, StatusCode: statusCode
    }

  });
});

In my original solution, I rendered my 404 Not Found page using an Angular component, so I wouldn't override the returned HTML (html: html, statusCode: statusCode).

And for the sake of completeness, here is the HttpStatusCodeService from the answer linked to above:

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;
  }
}

Let me know if this works. If it doesn't, I can try to get a test environment set up to poke at this some more, but no promises.

这篇关于ASP.Net Core 2.1 Angular SSR/Universal 返回 Http 状态码 404的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 02:18