Angular deep linking - Apache Tomcat
Asked Answered
S

3

6

I'm building an Angular app. It is hosted with base a href as /hris. So my base url to access the app will be domain.com/hris. Further, I have 3 different apps of which one is called term. So when I click on the term link it goes to domain.com/hris/term.

When the user directly tries to access the link domain.com/hris/term, it returns 404 with a message: HTTP Status 404 - /hris/term.

I don't want 404 to occur. How to get this done?

What I have done so far:

I tried to create a .htaccess file in the folder, where index.html resides.(I built the Angular app using ng build --base-href=/hris/). I deployed the dist folder to the server in a directory called hris.

In the .htaccess file I used the following variants, to no avail.

1

    <IfModule mod_rewrite.c>
          Options Indexes FollowSymLinks
          RewriteEngine On
          RewriteBase /hris/
          RewriteRule ^index\.html$ - [L]
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteCond %{REQUEST_FILENAME} !-d
          RewriteRule . index.html [L]
    </IfModule>

2

    <IfModule mod_rewrite.c>
       Options Indexes FollowSymLinks
       RewriteEngine On
       RewriteRule ^index\.html$ - [L]
       RewriteCond %{REQUEST_FILENAME} !-f
       RewriteCond %{REQUEST_FILENAME} !-d
       RewriteRule . /index.html [L]
    </IfModule>

3

    <IfModule mod_rewrite.c>
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} -s [OR]
        RewriteCond %{REQUEST_FILENAME} -l [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^.*$ - [NC,L]
        RewriteRule ^(.*) index.html [NC,L]
   </IfModule>

I am using Angular 5. Please let me know if my approach is right, or what I have to do to get this going.

Version: Apache Tomcat 7- Version 7.0.64

Selway answered 26/4, 2018 at 15:23 Comment(0)
H
9

".htaccess" files do not work on Tomcat. Put the rewriting config into a file WEB-INF/rewrite.conf, maybe like this:

RewriteCond %{SERVLET_PATH} !-f
RewriteRule ^/(.*)$ /index.html [L]

Next you need to add a file called META-INF/context.xml which enables the rewriting, i.e.:

<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true" tldValidation="false" xmlValidation="false">

  <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />

</Context>

Also remove the HashLocationStrategy from your Angular app.

Update

Why rewriting

  • Since Angular apps are SPAs the only real page that gets addressed at all is index.html.
  • Therefore any link like an href would leave that page and quit the app.
  • Angular uses its Router to redirect to virtual paths inside the app, without leaving index.html.
  • A web server would guess these paths are real files and since they do not exist, respond with an 404 HTTP status (in case of Tomcat its the DefaultServlet serving static content).
  • To get around this problem url rewriting can be used.

How to enable rewriting

  • First you need to enable the RewriteValve, which is a network filter and is disabled by default. To do so, you can add a context.xml to your Angular build file, like in the example above (portable version), or add it to the server.xml (server-side version). See code snippets above.
  • After that add a rewrite.conf file to setup the rewriting conditions. See code snippets above.
  • In the example above the first line tells Tomcat to look for "files which are not real/existing files" !-f, in the current servlet path. The servlet path part is neccessary, if your app is not deployed as ROOT (i.e. www.xyz.com/**myApp**) and will be set accordingly.
  • The second line mapps every "virtual path" from the Angular router to index.html.

Update 2

Hose answered 27/4, 2018 at 7:48 Comment(4)
Could you please provide some links that go in more details on your answer? I thought one could configure an .htaccess for tomcat as well. Thanks a lot!Tacho
Thanks a lot! I should create WEB-INF/rewrite.conf and then META-INF/context.xml inside the src folder of my Angular project?Tacho
Yes, but you need to make sure they both end up in the dist folder after build. So you need to add them to angular.json in the assetssection. Run ng build after all and check the dist folder.Hose
I tried this a couple of times but somehow I can't get it to work. After running ng build the META-INF and WEB-INF folders are indeed in the dist folder. If I do these changes in the server files on the other hand (server.xml or creating a rewrite.conf file) then it works.Tacho
W
3

For fixing the deep link issue when deploying angular application (with PathLocationStrategy routing) on apache tomcat server (8, 9) -

  1. Configure the RewriteValve in server.xml
  2. Write the rewrite rule in rewrite.config

server.xml -

...
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />

...
      </Host>
...

rewrite.config - (note - /hello/ is the context path of the angular app on tomcat)

RewriteCond %{REQUEST_PATH} !-f
RewriteRule ^/hello/(.*) /hello/index.html

I have documented this in my article - Fixing deep linking issue – Deploying angular application on Tomcat server

Walling answered 10/4, 2019 at 12:13 Comment(1)
I have tried this, but I'm encountering a problem: each of the three javascript files (runtime.###.js, main.###.js, and polyfills###.js) are ALSO being replaced by the contents of index.html. So the page fails to load. Any idea why?Flyblow
P
3

I stumbled on this question while attempting solve a similar issue. stefan's answer worked for me with a slight modification to the file name. Per https://tomcat.apache.org/tomcat-9.0-doc/rewrite.html, the rewrite configuration file should be named rewrite.config (not rewrite.conf).

I do not have enough rep to comment on his answer so I will reiterate here for completeness:

Put the rewriting config into a file WEB-INF/rewrite.config, maybe like this:

RewriteCond %{SERVLET_PATH} !-f
RewriteRule ^/(.*)$ /index.html [L]

Next you need to add a file called META-INF/context.xml which enables the rewriting, i.e.:

<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true" tldValidation="false" xmlValidation="false">
  <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
</Context>

Also remove the HashLocationStrategy from your Angular app.

Psychosomatic answered 7/8, 2020 at 16:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.