rewrite rules for apache 2 to use with angular js

Obviously, there are a lot of mod rewrite discussions and answers all across the web. However, I am having a hard time grasping them. So I thought I would ask here.

I’m asking for rewrite rules to do what Andy Joslin explained in the comments here: https://stackoverflow.com/a/11100438

This is my current dir structure at the root of example.com

  • app/
  • app/index.html (the “root” of the angular js application)
  • api (This will be a symfony 2 app that is used for the ‘api’. I’ll be sending ajax requests to and from here from angular.)

I would like to redirect all requests to app/index.html except for requests to /api.

For example:

http://example.com/categories/electronics/ipod would actually be like going to http://example.com/app/index.html/categories/electronics/ipod

I would like for the app/index.html part to be hidden however.

Then, there would be an exception for requests to http://example.com/api because I will need to make ajax requests to those url paths.

Thanks for any and all help/guidance.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

The accepted answer to this question is outdated. You can now use the FallbackResource directive in your conf file with Apache 2.2.16+.

FallbackResource /app/index.html

If you want the FallbackResource directive to ignore the “/api” routes:

<Directory /api>
FallbackResource disabled
</Directory> 

Solution 2

Here’s something to get you going (put this inside your /.htaccess file):

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !/api

# otherwise forward it to index.html 
RewriteRule ^.*$ - [NC,L]
RewriteRule ^app/. /app/index.html [NC,L]

NOTE: For newer Apache versions see also the next answer, which uses the much easier FallbackResource

Solution 3

The problem with this answer is that you still want 404s for file-not-found. Depending on how a person is building their front-end application, its very common for people to have css or other files return 404, especially if they are building larger dynamic applications, or are outsourcing the front-end work. Also, angular routes are usually not related to anything on the file system. The above may work if you narrow it down to a single directory. For instance, I will often use a common prefix for all angular routes that is not related to the file-system layout (/ajs/). If you can do

<Directory /ajs>
FallbackResource /app/index.html
</Directory> 

Then it would make more sense, but that doesn’t seem to work for me. Using a common prefix also makes the backend rules much simpler no matter the backend. For instance, you can setup a simple server forward controller if you aren’t using a reverse proxy. And it makes modeling your apache rewrite rules simple. For instance:

RewriteEngine On
RewriteRule ^/ajs/(.+)$ /index.html

That said, I haven’t seen the directory/fallback method before, so am interested to explore it for when the only rewrite I need is for the angular forward. Thanks!

Solution 4

This is a slight variation and elaboration of Scott Ferguson’s excellent answer. I find it easier to use the <Location> directive than <Directory>. The <Directory> directive takes an absolute path name which can be different in different machines.

So, let’s say that your Angular app’s index.html is in my-app/index.html under the document root of your web server. And you wish to access the app using http://localhost/my-app.

First of all make sure that your base href is “/my-app/”. Next, in your httpd.conf file add:

<Location "/my-app">
    FallbackResource /my-app/index.html
</Location>

This will cause Apache to load index.html if any resource under /my-app/ can not be found.

If you are making API calls under the same path, such as say /my-app/api then you should probably not apply the FallbackResource rule for these calls. So add:

<Location "/my-app/api">
    FallbackResource disabled
</Location>

Solution 5

From my production server:

<VirtualHost *:80>
        ServerName XXX.com

        DocumentRoot /home/www/XXX.com/www

        # Local Tomcat server
        <Location /api/>
          ProxyPass http://localhost:8080/api/
          ProxyPassReverse http://localhost:8080/api/
        </Location>

        RewriteEngine On

        # If an existing asset or directory or API is requested go to it as it is
        RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
        RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]
        RewriteCond %{REQUEST_URI} /api
        RewriteRule ^ - [L]

        # If the requested resource doesn't exist (and is not API), use index.html
        RewriteRule ^ /index.html

        ErrorLog logs/XXX.com-error.log
        CustomLog logs/XXX.com-access.log common
</VirtualHost>

Please note, that “!” before “/api” in the accepted answer is incorrect.

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply