首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASP.Net Core2.1角SSR/通用返回Http状态码404

ASP.Net Core2.1角SSR/通用返回Http状态码404
EN

Stack Overflow用户
提问于 2018-06-19 18:36:26
回答 2查看 1.8K关注 0票数 1

SpaPrerenderingExtensions内核2.0 JavaScriptServices中提供了HTTP代码之后,我们似乎可以从JavaScriptServices应用程序返回HTTP代码,SpaPrerenderingExtensions将使用该应用程序将HTTP代码返回给客户端。

如果您在SpaPrerenderingExtensions中查看下面的方法

代码语言:javascript
复制
private static async Task ServePrerenderResult(HttpContext context, RenderToStringResult renderResult)

SpaPrerenderingExtensions的完整代码可在这里获得:https://github.com/aspnet/JavaScriptServices/blob/8ded472fe93123079ab97c9332f24460340876d2/src/Microsoft.AspNetCore.SpaServices.Extensions/Prerendering/SpaPrerenderingExtensions.cs

您将注意到,renderResult.Html包含从角服务器应用程序返回的html标记,而renderResult.StatusCode.Value包含状态代码。

启用SSR的官方文档(可在https://learn.microsoft.com/en-us/aspnet/core/spa/angular?view=aspnetcore-2.1&tabs=visual-studio#server-side-rendering上获得)建议将以下代码添加到main.server.ts文件中。

代码语言:javascript
复制
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 }));
});

请任何人指导我如何返回状态代码从角服务器应用程序,以使它正确地被ASP.Net Core 2.0 SpaPrerenderingExtensions拾取。

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

注意:我使用的是ASP.Net Core2.1角CLI 6的模板。

EN

回答 2

Stack Overflow用户

发布于 2018-06-19 22:53:24

好的,我尝试了下面的方法,它似乎是有效的,任何反馈和改进都将受到高度欢迎。我不确定这种方法是否线程安全。我的意思是,如果服务器提供并发请求,那么是否有可能将一个请求的状态代码分配给其他请求,因为这种方法利用了constant对象的子属性是可变的这一事实。

我创建了一个文件globals.ts ,其代码如下:

代码语言:javascript
复制
export const response = { statusCode: 200 };

然后,我创建了一个服务StatusCodeService

代码语言:javascript
复制
import { Injectable } from '@angular/core';
import * as myGlobals from './globals';

@Injectable()
export class StatusCodeService {

  setStatusCode(statusCode: number) {
    myGlobals.response.statusCode = statusCode;
  }

}

现在,每当我必须设置状态代码时,我都会使用此服务来设置状态代码。

我还用下面的代码更新了main.server.ts 文件,以便将值传递给服务器:

代码语言:javascript
复制
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';

import * as myGlobals from './app/globals';

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) => {

    let statusCode: number = 200;
    if (myGlobals.response.statusCode == 404) {
      statusCode = 404;
      //reset status code to 200 for next request
      myGlobals.response.statusCode = 200;
    }

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

  });
});

我也尝试了 在aspnet核SPA角度应用程序中返回404状态码中提到的方法

我更新了角6的main.server.ts文件。

代码语言:javascript
复制
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { APP_BASE_HREF } from '@angular/common';

import { first } from 'rxjs/operators';

import { enableProdMode, ApplicationRef, NgZone } from '@angular/core';
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
import { AppServerModule } from './app/app.module.server';

import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

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

  const providers = [
    provideModuleMap(LAZY_MODULE_MAP),
    { provide: INITIAL_CONFIG, useValue: { document: '<app-root></app-root>', url: params.url } },
    { provide: APP_BASE_HREF, useValue: params.baseUrl },
    { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
  ];

  return platformDynamicServer(providers).bootstrapModule(AppServerModule).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.pipe(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();
        });
      });
    });
  });
});

但当我运行这个应用程序时,它几乎坏了,有以下问题:

  • 生成的标记中没有任何样式表。缺少服务器传输状态。fxFlex布局不起作用。
票数 0
EN

Stack Overflow用户

发布于 2018-06-28 21:45:58

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

提供给renderModule()renderModuleFactory()renderModule()参数对象有一个extraProviders数组,我相信它将允许我们向AppServerModule模块添加额外的提供程序。

以下是我的想法:

  • 使用我在这里回答的HttpStatusCodeService在aspnet核SPA角度应用程序中返回404状态码
  • 将其添加到providers模块中的AppBrowserModule数组(只有浏览器模块,而不是服务器模块)。
    • 这将允许在应用程序在浏览器中运行时正常地注入服务。

  • HttpStatusCodeService文件中实例化main.server.ts,并将该实例作为extraProviders数组中的提供程序添加。
    • 这将允许在应用程序在服务器上运行时注入服务,同时也向我们提供对注入服务的引用。

  • 使用对服务的引用来确定响应是否需要404。

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

代码语言:javascript
复制
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
    }

  });
});

在我最初的解决方案中,我使用一个角组件呈现了我的404 Not页面,所以我不会覆盖返回的HTML (html: html, statusCode: statusCode)。

为了完整起见,下面是链接到上面的答案的HttpStatusCodeService

代码语言:javascript
复制
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;
  }
}

如果这有用的话请告诉我。如果没有,我可以尝试设置一个测试环境,以便更多地了解这一点,但没有承诺。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50934948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档