skip to Main Content

I recently developed and published my first large angular project (I am still relatively new to angular). For better SEO I decided to look into static prerendering using both Scully and Angular Universal, both have one critical issue, so google search console & Bing webmaster refuses to rank most of my routes because of Redirect issues (301 redirect).

So what happens is that, after the page is prerendered the urls is adding an extra slash "/" at the end, then after few seconds angular starts and makes a redirected javascript to the correct page.

the prerender page will make the url like

https://www.mywebsite.com/page1/

then after some time redirects to

https://www.mywebsite.com/page1

the first url is the one prerendered

google search console & Bing webmaster consider both of these routes as redirects and are therefore not indexed, when the one without "/" is visited, slash is first added and then removed (therefore a redirect ) and similarly when the one with "/" is visited it is redirected to remove the slash. Prerendering is supposed to help in SEO but it is instead hurting SEO, I’ve checked and these are indeed 301 redirects, Am I doing something wrong here? I searched about this issue all around the internet but found no solution. Can someone please help me with this.

Screenshot of Google search console:

As you can see in the screenshot most of my pages are not indexed with the reason given as pages with redirect or redirect error

3

Answers


  1. Chosen as BEST ANSWER

    I finally figured it out

    Short answer: Because of the way angular universal pre-rendering works you can't remove "/" at the end for the pre-rendered pages, Your only solution is to make all your routes end with "/" by default, so when angular starts and is redirecting it will also redirect to the exact same url hence not counting as a redirect

    Long answer:

    Why is this happening?

    First we need to understand why is this happening in the first place. So the way angular pre-rendering works is that for each route a directory/folder by the name of that route is generated with an "index.html" file inside. So lets say if I have a route "mywebsite.net/page1", angular universal will generate a directory "page1" with an index.html file inside containing the html code of that page. In both nginx and apache servers a directory is represented by a "/" relative to the base directory. So if the server want to access index.html file inside of that page1 folder the path would be represented as "/page1/", notice the trailing slash in the end meaning we are inside the page1 directory, alternatively if we had a "page1.html" file at the root directory that would be represented as "/page1" but that's not how angular universal generates it's pages, as mentioned above it generates directories with index.html files inside.

    Why is there a 301 redirect

    So when we first visit any route let's say "/page1", our server goes inside the page1 directory and opens up index.html file inside, and because it is a directory and not a file in the root directory it adds "/" in the end and once that index.html file is rendered the angular script runs it redirect you to the route you have defined in your angular routes, if it is without a "/" it will redirect to it, hence removing the slash. This is why slash is added and then removed

    Solution

    The solution is to make all your routes end with a trailing slash by default. In you every module you will define your routes as

    const routes: Routes = [
    { path: 'page1/.', component: page1Component, data: { title: "page q", subTitle: " " } },
    ...
    ];
    

    notice "/." at then end of the path and in your

    <a href="" routerLink="/page1/.">Page1</a>
    

    and in your main.ts you can add some logic to add a trailing slash to the links without one. something like this

    import { Location } from '@angular/common';
    
    const __stripTrailingSlash = (Location as any).stripTrailingSlash;
    (Location as any).stripTrailingSlash = function _stripTrailingSlash(url: string): string {
      const queryString$ = url.match(/([^?]*)?(.*)/);
      if (queryString$[2].length > 0) {
        return /[^/]/$/.test(queryString$[1]) ? queryString$[1] + '.' + queryString$[2] : __stripTrailingSlash(url);
      }
      return /[^/]/$/.test(url) ? url + '.' : __stripTrailingSlash(url);
    };
    

    Doing all this fixes the redirect issue.


  2. I answered this once but @Dharman felt this was a duplicate answer but this is a different issue because it involves Scully and an Apache Server. The other one I answered had differences on this front.

    If anyone is looking for answers for this you can check out my answer here and get some inspiration for the differences this question provides since moderators will delete it if I give you helpful hints here:

    https://stackoverflow.com/a/73835009/5832236

    Login or Signup to reply.
  3. I had the same issue with redirects 301.

    Well, the redirects are initiated by a server, therefore it might be a better solution to tweak the server configuration instead of adapting the code for unusual/undesired behavior.

    In my case, it is scully and nginx, which the classical standard configuration

    location / {
      try_files $uri $uri/ /index.html;
    }
    

    This means that the server is looking for

    1. a file to serve as an exact match $uri.

    2. If not found, it looks if a folder exists with this exact name $uri/.

    3. If the folder exists, the server performs an internal redirect into it and serves the index.html which is located inside it (if it is there).

    4. If none is found, it performs an internal redirect to /index.html in the root folder.

    This is exactly the case for pre-rendered angular apps, where for each route a pre-renderer creates a folder with the corresponding name and places an index.html file inside it.

    In order to serve the index.html file from a requested route directly, it is sufficient to modify the location configuration as follows

    location / {
      try_files $uri $uri/index.html /index.html;
    }
    

    Here server responds with an exact match $uri, and if not found, with a file index.html in the specified folder $uri without a redirect.

    I guess a similar configuration can be made for another type of server.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search