Angular Universal 页面返回正确的响应码,比如 404 Not Found
默认通过 Angular 创建的 Angular Universal 项目,在路由配置中使用通配符 ** 仅仅只是进行路由跳转。
{
path: '**', redirectTo: '/not-found'
}
运行在 node express 环境下时,即使在页面内通过下方代码发送 http 状态码依然无法正确返回如 404 之类的响应码,只会以 200 返回。
如果没有正确返回响应码,在生产环境下使用,则会出现这个问题:没有正确返回状态码,搜索引擎爬虫认为这是一个正常的页面,将会被爬取并索引,导致用户在搜索引擎搜索结果中访问到错误页,在用户眼里这可能无关紧要,但是对于搜索引擎来说,这是十分重要的,不处理将会对网站排名造成巨大的影响。
在页面中设置状态码
新增页面组件 not-found,并修改 not-found.component.ts:
import { Component, OnInit, Optional } from '@angular/core';
import { PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { RESPONSE } from "@nguniversal/express-engine/tokens";
import { Response } from 'express';
@Component({
selector: 'app-not-found',
templateUrl: './not-found.component.html'
})
export class NotFoundComponent implements OnInit {
constructor(
@Inject(PLATFORM_ID) private platformId: Object,
@Optional() @Inject(RESPONSE) private response: Response
) {
}
ngOnInit() {
if (!isPlatformBrowser(this.platformId)) {
if (this.response) {
this.response.status(404); // 通过 RESPONSE 设置 HTTP 状态码,这里设置为 404
this.response.statusMessage = 'Not Found'; // 设置 HTTP 响应实体内容
}
}
}
}
上方代码运行在服务端渲染模式下,请求页面会返回一个HTTP响应码为 200 的 html 页面,这是因为在 server.ts 中没有使用 ngExpressEngine 函数处理响应并返回HTML页面。
ngExpressEngine() 是对 Universal 的 renderModule() 函数的封装。它会把客户端请求转换成服务端渲染的 HTML 页面。 你还要在某个适用于你服务端技术栈的模板引擎中调用这个函数。
第一个参数是 AppServerModule 。 它是 Universal 服务端渲染器和你的应用之间的桥梁。
第二个参数 extraProviders 是可选的。它能让你指定一些在服务端运行时特有的服务提供商。 只有当你的应用需要一些运行在服务器中才需要的信息时,才需要这么做。 比如这个运行中的服务器的源地址,当像前面例子中那样无法使用 Request 令牌时,可用它来计算 HTTP URL 的绝对地址。
ngExpressEngine() 函数返回了一个会解析成渲染好的页面的承诺( Promise )。 接下来你的引擎要决定拿这个页面做点什么。 在这个引擎的 Promise 回调函数中,把渲染好的页面返回给了 Web 服务器,然后服务器通过 HTTP 响应把它转发给了客户端。
Angular 9 的解决方案
需要通过修改 src/server.ts 内 app.engine 代码: 首先在代码开始处顶部引入下方的内容:
import {REQUEST, RESPONSE} from '@nguniversal/express-engine/tokens';
app.engine('html', (path, options, callback) => ngExpressEngine({
bootstrap: AppServerModule,
providers: [
provideModuleMap(LAZY_MODULE_MAP),
{
provide: REQUEST,
useValue: options.req,
},
{
provide: RESPONSE,
useValue: options.req.res,
},
]
})(path, options, callback)
);
低于 Angular 9(比如 Angular 8 等) 的解决方案
同样需要通过修改 src/server.ts 内 app.engine 代码: 首先在代码开始处顶部引入下方的内容:
import {REQUEST, RESPONSE} from '@nguniversal/express-engine/tokens';
app.engine('html', (path, options, callback) => ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP),
{
provide: REQUEST,
useValue: options.req,
},
{
provide: RESPONSE,
useValue: options.req.res,
},
]
})(path, options, callback)
);
以上的代码都是基于 Angular 默认生成的代码修改的。
重新运行服务端渲染项目,访问页面 not-found 即可在开发者工具中查看到正确的响应码了。