在SpaPrerenderingExtensions内核2.0 JavaScriptServices中提供了HTTP代码之后,我们似乎可以从JavaScriptServices应用程序返回HTTP代码,SpaPrerenderingExtensions将使用该应用程序将HTTP代码返回给客户端。
如果您在SpaPrerenderingExtensions中查看下面的方法
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文件中。
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的模板。
发布于 2018-06-19 22:53:24
好的,我尝试了下面的方法,它似乎是有效的,任何反馈和改进都将受到高度欢迎。我不确定这种方法是否线程安全。我的意思是,如果服务器提供并发请求,那么是否有可能将一个请求的状态代码分配给其他请求,因为这种方法利用了constant对象的子属性是可变的这一事实。
我创建了一个文件globals.ts ,其代码如下:
export const response = { statusCode: 200 };然后,我创建了一个服务StatusCodeService
import { Injectable } from '@angular/core';
import * as myGlobals from './globals';
@Injectable()
export class StatusCodeService {
setStatusCode(statusCode: number) {
myGlobals.response.statusCode = statusCode;
}
}现在,每当我必须设置状态代码时,我都会使用此服务来设置状态代码。
我还用下面的代码更新了main.server.ts 文件,以便将值传递给服务器:
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文件。
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();
});
});
});
});
});但当我运行这个应用程序时,它几乎坏了,有以下问题:
发布于 2018-06-28 21:45:58
我将此作为一个答案,因为我可以比在评论中更好地格式化事情,但是这都是未经测试的,并且是基于查看我过时的解决方案、上面的代码片段和Angular6文档(我没有最新的VS模板,所以现在无法进行测试)。
提供给renderModule()和renderModuleFactory()的renderModule()参数对象有一个extraProviders数组,我相信它将允许我们向AppServerModule模块添加额外的提供程序。
以下是我的想法:
HttpStatusCodeService:在aspnet核SPA角度应用程序中返回404状态码providers模块中的AppBrowserModule数组(只有浏览器模块,而不是服务器模块)。
HttpStatusCodeService文件中实例化main.server.ts,并将该实例作为extraProviders数组中的提供程序添加。
下面是我的未测试的尝试修改您的main.server.ts文件片段以使其工作。
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:
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;
}
}如果这有用的话请告诉我。如果没有,我可以尝试设置一个测试环境,以便更多地了解这一点,但没有承诺。
https://stackoverflow.com/questions/50934948
复制相似问题