A website I am working on is using Angular Universal 10.1.1 and is hosted on an IIS Server. An example of this happening is https://tragoa.com/welcome
If I navigate to the page from the root like foo.com then the website goes straight to the correct route foo.com/welcome without a 301 redirect. However, if I attempt to load foo.com/welcome directly then it will return that request with a 301 redirect to foo.com/welcome/ and that redirect request is returned with a 200 OK and then the trailing slash is stripped in the url bar. So it goes:
- Request with no trailing slash (/welcome)
- A 301 redirect returned to request with location including the trailing slash (/welcome/)
- 200 OK returned
- Trailing slash stripped in the URL bar in browser
The main issue here is the unwanted redirect
This only occurs when the page is using the prerendered HTML. It does not redirect if there is no prerendered index HTML for the given route.
This has caused issues with Lighthouse and some 3rd party redirect issues.
Does anyone know what could be causing this?
Some information that may help:
The base href of the html is <base href="/">
NOTE: I change this to not have the / then the routes get doubled up like foo.com/welcome/welcome
My server.ts get is this:
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { existsSync, readFileSync } from 'fs';
import 'localstorage-polyfill';
const domino = require('domino');
let distFolder = join(process.cwd(), '../spa/browser');
const template = readFileSync(join(distFolder, 'index.html')).toString();
const win = domino.createWindow(template);
win.Object = Object;
win.Math = Math;
global['window'] = win;
global['document'] = win.document;
global['branch'] = null;
global['object'] = win.object;
global['HTMLElement'] = win.HTMLElement;
global['navigator'] = win.navigator;
global['localStorage'] = localStorage;
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
export function app(): express.Express {
const server = express();
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index.html';
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
server.get(
'*',
(req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run(): void {
const port = process.env.PORT || 4000;
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
I use this command to create my site and then deploy the files "prerender": "ng build --configuration production && ng run my-app.spa:prerender:production"