Search code examples
angularspring-bootseourl-routing

Removing # from URL does not work after deployment - HTTP 404


I am trying to get rid ot #-red URLs in my Angular app (Google recommends it in the case that your app does not present indexable content on the first load). The web application is in the static/ directory of my Spring Boot application.

So I disabled the use of #:

export const AppRouting = RouterModule.forRoot(routes, {
  useHash: false,
  enableTracing: false
});

On my local machine evereything works fine e.g.

http://localhost:4200/cars/berlin

lists all cars in Berlin but

http://www.example.com/cars/berlin

Gives me HTTP 404 after deploying the site.

I'm not sure why this happens. How can I fix this?

However, the root URL http://example.com is working correctly. The content of the website is displayed but any page below cannot be reached.


Solution

  • This is what I ended up doing. It is simpler as the length of this answer might suggest.


    1) Move apps to separate paths

    I moved all my apps (there are two at the moment) to sub-directories. This means that all my apps are required to work under a base-href as in

    www.example.com/admin-tool/index.html
    www.example.com/web/index.html
    

    This is the ng command I am using to build the admin-tool app:

    #!/usr/bin/env bash
    
    BASE_HREF=admin-tool
    
    ng build --aot --prod --base-href /$BASE_HREF/ --output-hashing none --output-path dist/$BASE_HREF --deploy-url /$BASE_HREF/
    

    2) Move apps to the Spring project

    Move/copy the content in dist/ (the output of the ng build) to (in my case) src/main/resources/static if you're not building it there already:

    src/main/resources/static/admin-tool
    src/main/resources/static/web
    

    3) Do the necessary forwarding

    As mentioned in other answers one now has to forward requests to the respective index.html "files" (let's just call it like that).

    Here is why (as I understand it): Before we did all this, Angular just worked on #-ed path which caused the JS code to do the updates based on what's after the #. And if I'm getting it right - removing the # will essentially mean that the browser is now making GET requests for all those URLs. So from the cars example, if I have a place/route http://www.example.com/web/cars/berlin then this will now be a GET request which the server has to handle - in this case forward it to the correct endpoint.

    Below is the code I am using in my backend to accomplish this:

    @Controller
    public class ForwardController {
    
        @RequestMapping(value = "/*")
        public String rectRoot(HttpServletRequest request) {
            return "forward:/web/index.html";
        }
    
        @RequestMapping(value = "/**/{[path:[^\\.]*}")
        public String redirect(HttpServletRequest request) {
    
            if (request.getRequestURI().startsWith("/admin-tool")) {
                return "forward:/admin-tool/index.html";
            } else if (request.getRequestURI().startsWith("/web")) {
                return "forward:/web/index.html";
            }
    
            return "forward:/web/index.html";
        }
    }
    

    I don't give it a 100% yet, and I really hope this is just a workaround, but so far I am not having any issues with it.

    Now here is why I am doing all this:

    Apparently it's recommended to move away from #-ed paths for several reasons. Since I am using Angular, I'll have to walk a few more miles in order to get search engine optimization (SEO) going but from what I get ([1], [2], [3]) you should avoid it since Google does not index it. They might only use it as an anchor but if you have AJAX content behind your # you're going to have a bad time.

    See further [4] about #! which also seems to be deprecated by now and also take a look at [5] and [6].


    [1] https://www.oho.com/blog/explained-60-seconds-hash-symbols-urls-and-seo

    [2] https://www.seroundtable.com/google-no-hashtags-in-urls-26537.html

    [3] https://www.seroundtable.com/google-no-url-fragments-23449.html

    [4] https://webmasters.stackexchange.com/a/18606/64452

    [5] https://webmasters.googleblog.com/2015/10/deprecating-our-ajax-crawling-scheme.html

    [6] https://snipcart.com/blog/angular-seo-universal-server-side-rendering