Angular v17 SSR with SSG keeps redirecting 301

Discussão em 'Angular' iniciado por M. Yilmaz, Março 23, 2025.

  1. M. Yilmaz

    M. Yilmaz Guest

    When I go to my web app and click on one of the routerLink, the server runs a .js module to display the content. When I refresh that exact page (which is pre-rendered) I get a 301 error.

    url/cases, 301, location: url/cases/

    I get a 200 code on url/cases/ after

    .htacces

    <IfModule Litespeed>
    RewriteEngine On

    # Redirect www to non-www and HTTP to HTTPS
    RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
    RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

    # Existing rules for handling files and serving index.html
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    RewriteRule ^(.*) /index.html [NC,L]
    </IfModule>



    server.ts

    import 'zone.js/node';

    import { APP_BASE_HREF } from '@angular/common';
    import { CommonEngine } from '@angular/ssr';
    import * as express from 'express';
    import { existsSync } from 'node:fs';
    import { join } from 'node:path';
    import AppServerModule from './src/main.server';

    // The Express app is exported so that it can be used by serverless Functions.
    export function app(): express.Express {
    const server = express();
    const distFolder = join(process.cwd(), '../browser');
    const indexHtml = existsSync(join(distFolder, 'index.original.html'))
    ? join(distFolder, 'index.original.html')
    : join(distFolder, 'index.html');

    const commonEngine = new CommonEngine();

    server.set('view engine', 'html');
    server.set('views', distFolder);

    // Example Express Rest API endpoints
    // server.get('/api/**', (req, res) => { });
    // Serve static files from /browser
    server.get(
    '*.*',
    express.static(distFolder, {
    maxAge: '1y',
    redirect: false
    })
    );

    // All regular routes use the Angular engine
    server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;

    const requestedPath = `${distFolder}${originalUrl}`;

    // Check if the requested path corresponds to an existing file
    if (existsSync(requestedPath)) {
    // Serve the file directly without rendering Angular
    return res.sendFile(requestedPath);
    }

    commonEngine
    .render({
    bootstrap: AppServerModule,
    documentFilePath: indexHtml,
    url: `${protocol}://${headers.host}${originalUrl}`,
    publicPath: distFolder,
    providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
    })
    .then((html) => res.send(html))
    .catch((err) => next(err));
    });

    return server;
    }

    function isRunningOnApachePassenger(): boolean {
    return moduleFilename.includes('lsnode.js');
    }

    function run(): void {
    // Start up the Node server
    const server = app();

    if (isRunningOnApachePassenger()) {
    server.listen(() => {
    console.log('Node Express listening to Passenger Apache');
    });
    return;
    }

    const port = process.env['PORT'] || 4000;

    server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
    });
    }

    // Webpack will replace 'require' with '__webpack_require__'
    // '__non_webpack_require__' is a proxy to Node 'require'
    // The below code is to ensure that the server is run only when not requiring the bundle.
    declare const __non_webpack_require__: NodeRequire;
    const mainModule = __non_webpack_require__.main;
    const moduleFilename = (mainModule && mainModule.filename) || '';
    if (
    moduleFilename === __filename ||
    moduleFilename.includes('iisnode') ||
    isRunningOnApachePassenger()
    ) {
    run();
    }

    export default AppServerModule;


    my routes:

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';

    const routes: Routes = [
    {
    path: '',
    loadChildren: () =>
    import('./pages/home/home.module').then((m) => m.HomeModule),
    },
    {
    path: 'over-ons',
    loadChildren: () =>
    import('./pages/over-ons/over-ons.module').then((m) => m.OverOnsModule),
    },
    {
    path: 'contact',
    loadChildren: () =>
    import('./pages/contact/contact.module').then((m) => m.ContactModule),
    },
    {
    path: 'expertises',
    loadChildren: () =>
    import('./pages/expertises/expertises.module').then((m) => m.ExpertisesModule),
    },
    {
    path: 'expertises/:slug',
    loadChildren: () =>
    import(
    './pages/expertises/expertise-detail/expertise-detail.module'
    ).then((m) => m.ExpertiseDetailModule),
    },
    {
    path: 'cases',
    loadChildren: () =>
    import('./pages/cases/cases.module').then((m) => m.CasesModule),
    },
    {
    path: 'cases/:slug',
    loadChildren: () =>
    import('./pages/cases/case-detail/case-detail.module').then(
    (m) => m.CaseDetailModule
    ),
    },
    {
    path: 'blogs',
    loadChildren: () =>
    import('./pages/blogs/blogs.module').then((m) => m.BlogsModule),
    },
    {
    path: 'blogs/:slug',
    loadChildren: () =>
    import('./pages/blogs/blog-detail/blog-detail.module').then(
    (m) => m.BlogDetailModule
    ),
    },
    ];

    @NgModule({
    imports: [
    RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled',
    anchorScrolling: 'enabled',
    scrollOffset: [0, 150]
    }),
    ],
    exports: [RouterModule],
    })
    export class AppRoutingModule {}


    I tried a few methods like changing the server.ts by adding a redirect: false and adjusting my routing to have ./ at the end. I also tried modifying my .htaccess but I couldn't get it to work.

    I'm trying to fix it so I can improve my SEO.

    Continue reading...

Compartilhe esta Página