34

There has been a lot of questions about this. I've been browsing them for days. I tried everything, and neither worked. Yes, I've checked angular.io too, and that didn't work either. So please, can someone come up with the ultimate answer or point me to one which I've probably not seen yet?

Here is this URL, a deep link to an Angular app called whatever and its someroute route with a parameter.

http://somedomain.com/whatever/someroute/123456

Of course it results in a 404 error. The web server has to be configured. My server runs nginx and I did this:

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

Now it redirects every site's 404 error on this server to my Angular app, but that's a secondary issue. The problem is that the route still doesn't want to kick in. The default / route is invoked every time, and not /someroute/123456.

Instead of pointing to various tutorials which I've probably already seen and tried, can someone briefly explain what is the trivial point I missed?

Tamás Polgár
  • 2,082
  • 5
  • 21
  • 48
  • you want to be able to go to angular app routes by a link and not navigating from the app? – LLL Jul 01 '17 at 21:31
  • Yes, exactly. The user should be able to reach deep links within the Angular app by direct links. For example by clicking a link to the registration confirmation in an e-mail he received. – Tamás Polgár Jul 01 '17 at 21:59

4 Answers4

20

It sounds like you may be missing the <base href=""> tag. This tag tells the Angular router what the base URI is for your application. If this is not present then Angular assumes that the initial navigation URI (in your case, /whatever/someroute/123456) is the base URI and all subsequent routing will be performed relative to that URI.

Try including <base href="/whatever/"> in the <head> element of your index.html to direct the router accordingly.

You may also control the <base href=""> meta tag via ng build if you are using the Angular CLI:

ng build --base-href '/whatever/'
Mike Hill
  • 3,622
  • 23
  • 27
  • 1
    For the record, OP could likely use either this solution or @GreyBeardedGeek's solution to fix his problem. This solution will allow him to continue using the `pushState` method, while @GreyBeardedGeek's solution will make his page use the `location.hash` method. For a better comparison on these methods, see [this StackOverflow question](https://stackoverflow.com/questions/9340121/which-one-is-better-pushstate-or-location-hash). – Mike Hill Nov 02 '17 at 14:29
9

You can switch to the HashLocationStrategy, i.e.

RouterModule.forRoot(appRoutes, {useHash: true});

This results in all app urls being index.html, followed by "#" and then the routing information.

Since you're always going to index.html, regardless of the route, you won't get a 404 for any valid URL.

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
  • An update to my own answer from 4 years ago - see the other answers on this page for how to make this work without using Angular's `HashLocationStrategy`, particularly https://stackoverflow.com/a/60920653/982341 Today, I would use `HashLocationStrategy` only if there was some overriding reason to do so. – GreyBeardedGeek Oct 26 '21 at 13:12
4

This was tripping me up for a while too. But just for the record, the Angular deployment documentation has a good section about this which you can find here https://angular.io/guide/deployment#server-configuration

The bottom line is that if you navigate from outside your app to a location in your app (other than the root location "/") the browser sends a GET request to the server asking for the full URL. But since that URL is meant to be interpreted as a route in your front-end app and not as a resource in your back-end server the server will throw a 404 (unless you happen to have also set up your server as a static file server and there happens to be a resource at that location). So what you need to do is configure your server to respond with the front-end app assets instead of returning a 404, that way when the front-end app loads in the browser it can check the URL and engage it's routing logic.

Max Taggart
  • 699
  • 6
  • 12
  • 1
    We only had to wait 3 years for it to be properly documented. :D Thanks! – Tamás Polgár Jul 11 '20 at 04:09
  • Hi Max, I have tried the approaches mentioned in that documentation. My project uses Docker, I also configured the Dockerfile to use my Node.js server.js file to serve the project once deployed, I've used nginx and even .htaccess. None of them worked. The project is hosted on a Linux server. I don't want to use the hash location strategy. Could you point me to a resource that spells what might actually be wrong? – Benneee_ Jul 11 '20 at 12:55
1

I experienced the same difficulties to get NGINX 1.17 to work in combination with routing in Angular 9. I finally found an NGINX configuration that supports deep linking respectively routing and at the same time doesn't require the usage of Angular's HashLocationStrategy nor setting <base href="">.

The key difference that I made is that I added the root directive to the location block to specify the root directory that will be used to search for a file:

events {
    worker_connections 1024;
}

http {

    server {
        listen 80;

        location / {
            root /usr/share/nginx/html;
            try_files $uri $uri/ /index.html;
        }
    }
    include /etc/nginx/mime.types;
}

This NGINX configuration assumes that the content of Angular's dist folder resides in /usr/share/nginx/html/. With this configuration I don't experience any HTTP 404 errors for routes like /someroute/123456 (even when I reload the page in the browser by hitting F5 or when I navigate to this route directly).

philenius
  • 31
  • 1
  • 5