问题
I struggle to settle a 404 page that returns to navigators/crawlers a specific HTTP status code : 404. Following SSR guide in https://angular.io/guide/universal, my application is correctly served with SSR.
I set a 'PageNotfound' route in my app-routing.module.ts :
{path: '*', component: NotFoundComponent}
But obviously it still returns 200 as http return statuses. How I can change http return code for this specific route ?
回答1:
Although it is quite well-documented here https://github.com/angular/universal/tree/master/modules/express-engine the proposed token does not work.
It is simply undefined in SSR (in the client it is easy to mock it).
However there is a (very) dirty solution.
Just put some marker on your 404 page (change whatevervaluehere
to something unique and meaningless):
<!-- indicator for SSR to return 404 status code -->
<!-- MUST BE LEFT HERE -->
<input type="hidden" value="whatevervaluehere">
and in the server.ts
app.get('*', (req, res) => {
res.render('index', {
req,
res,
}, (err: Error, html: string) => {
res.status(html && html.includes('whatevervaluehere') ? 404 : html ? 200 : 500).send(html || err.message);
});
});
Again, very, very dirty. However, works.
回答2:
add this to the component NotFoundComponent
import {Component, Inject, OnInit, Optional, PLATFORM_ID} 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',
styleUrls: ['./not-found.component.scss']
})
export class NotFoundComponent implements OnInit {
constructor(@Inject(PLATFORM_ID) private platformId: Object,
@Optional() @Inject(RESPONSE) private response: Response) {
}
ngOnInit() {
if (!isPlatformBrowser(this.platformId)) {
this.response.status(404);
}
}
}
modify server.js file to this
import {REQUEST, RESPONSE} from '@nguniversal/express-engine/tokens';
import {ValueProvider} from '@angular/core';
app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
// Our index.html
document: template,
url: options.req.url,
extraProviders: [
// make req and response accessible when angular app runs on server
<ValueProvider>{
provide: REQUEST,
useValue: options.req
},
<ValueProvider>{
provide: RESPONSE,
useValue: options.req.res,
},
]
}).then(html => {
callback(null, html);
});
});
回答3:
For me the following snippet worked (Angular 8.2.11). No need to change the default server.ts file.
import { Component, OnInit, Inject, PLATFORM_ID, Optional } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { isPlatformServer } from '@angular/common';
import { Request } from 'express';
@Component({
selector: 'app-error-not-found',
templateUrl: './error-not-found.component.html',
styleUrls: ['./error-not-found.component.scss']
})
export class ErrorNotFoundComponent implements OnInit {
constructor(
@Inject(PLATFORM_ID) private platformId: any,
@Optional() @Inject(REQUEST) private request: Request
) { }
ngOnInit() {
if (isPlatformServer(this.platformId)) {
if (this.request.res) {
this.request.res.status(404);
}
}
}
}
And offcourse we need our routes to be something like this:
export const routes: Routes = [
...
{ path: '404', component: ErrorNotFoundComponent },
{ path: '**', redirectTo: '/404' }
];
来源:https://stackoverflow.com/questions/52663743/angular-6-ssr-a-true-404-not-found-page-with-an-404-http-status-code