I'm on Angular v20.2 using the new SSR API to define how my routes should be rendered. I've also switched to the new AngularAppNodeEngine as seen in the docs.
server.ts:
import { AngularNodeAppEngine, createNodeRequestHandler, writeResponseToNodeResponse } from '@angular/ssr/node';
import express from 'express';
const app = express();
const angularApp = new AngularNodeAppEngine();
app.use('*', (req, res, next) => {
angularApp
.handle(req)
.then(response => {
if (response) {
writeResponseToNodeResponse(response, res);
} else {
next(); // Pass control to the next middleware
}
})
.catch(next);
});
/**
* The request handler used by the Angular CLI (dev-server and during build).
*/
export const reqHandler = createNodeRequestHandler(app);
app.routes.ts:
export const routes: Route[] = [
{
path: '404',
loadComponent: () => import('./views/not-found/not-found.component').then(m => m.AppNotFoundComponent),
},
{
loadComponent: () => import('./views/page/page.component').then(m => m.AppPageComponent),
matcher: url => {
... some matching logic that works fine ...
},
}
];
app.routes.server.ts:
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '**',
renderMode: RenderMode.Server,
},
{
path: '404',
renderMode: RenderMode.Server,
status: 404,
headers: {
'Cache-Control': 'no-cache',
},
}
];
app.config.server.ts:
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering, withRoutes } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';
const serverConfig: ApplicationConfig = {
providers: [provideServerRendering(withRoutes(serverRoutes))],
};
export const config = mergeApplicationConfig(appConfig, serverConfig);
Then I just run this for when my server can't find a url:
this.router.navigateByUrl('/404', { skipLocationChange: true });
I've also tried without skipLocationChange: true:
this.router.navigateByUrl('/404');
But both give a 200 status code for the server request instead of 404. It does render the correct HTML though.
What am I missing in my configuration to get the status code to work properly?