24

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.

Community
  • 1
  • 1
Mike Haas
  • 1,773
  • 2
  • 19
  • 29

5 Answers5

28

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> 
Scott Ferguson
  • 369
  • 3
  • 13
17

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

Community
  • 1
  • 1
Stewie
  • 59,860
  • 19
  • 144
  • 113
  • Thanks, I'll use what I can from that. I'm working through a popular tutorial on rewrites now. I'm thinking though that what I want to do is not serve a file just because it exists. The problem with that is someone could request what angular calls a 'partial' file and it would serve it, etc. I'm going to redirect everything to app/index.html Then I'll explicitly skip certain directories such as css/ img/ – Mike Haas Mar 08 '13 at 02:36
  • 1
    This code almost solved my problem... I had to change the app rule a little bit, I left my working example on this answer: http://stackoverflow.com/a/15415902/54848 – elviejo79 Mar 14 '13 at 17:19
  • where to keep this file if using localhost:xxxx ? – Mr AJ Dec 30 '17 at 16:35
0

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!

Adam Marr
  • 43
  • 8
0

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>
RajV
  • 5,925
  • 6
  • 39
  • 54
0

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.

Andrey Minogin
  • 4,222
  • 5
  • 33
  • 55