Search code examples
javascript.htaccessurlurl-rewritinghtml5-history

Using .htaccess to navigate to parent directory of last directory in URL


I'm trying to write .htaccess code that will ignore the final subdirectory of a URL, route to the directory before that final subdirectory, but leave the URL intact.

This is in the context of an SPA in which I use JavaScript for routing.

If I navigate to directory xxx, which could be nested arbitrarily deeply:

https://my-site/[subdirectories]/xxx

...then when clicking on relative links within the xxx directory, such as to:

./aaa
./bbb
./ccc

...which would correspond to (and produce URLs of):

https://my-site/[subdirectories]/xxx/aaa
https://my-site/[subdirectories]/xxx/bbb
https://my-site/[subdirectories]/xxx/ccc

...then the JavaScript will detect the change in the URL and bring up the content for the "virtual" subdirectories aaa, bbb, ccc. Fine and dandy.

However, if I go to any of those URLs directly, i.e., by entering the URL directly, rather than using navigation within the site, then my site throws a 404 error, as the aaa, bbb, and ccc are not actual subdirectories. They are "virtual" subdirectories, not corresponding to actual folders on the server, and thus the error is thrown.

I want to write an .htaccess routine that will detect an initial navigation (direct opening of):

https://my-site/[subdirectories]/xxx/aaa
https://my-site/[subdirectories]/xxx/bbb
https://my-site/[subdirectories]/xxx/ccc

etc.

...and simply open this location:

https://my-site/[subdirectories]/xxx

...but preserve the "virtual" subdirectory on the end (aaa, bbb, ccc) in the URL as displayed in the URL bar. My JavaScript will take over from there to bring in the desired content for aaa, bbb, ccc. (And this works fine after first navigating to https://my-site/[subdirectories]/xxx directly and then simply clicking on links to aaa, bbb, ccc; it's going to any of those "subdirectories" directly that's the problem.)

Can this be done with .htaccess? I'm struggling.


Solution

  • The trick is to craft a rewrite rule that specifies a file for the destination content.

    If the subdirectory names are known, and for this example they are aaa, bbb, and ccc, then the following rule opens the index.html file in the subdirectory while leaving the URL intact:

    RewriteEngine on
    
    # If it's not an actual directory...
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # If it's not an actual file...
    RewriteCond %{REQUEST_FILENAME} !-f
    
    # Provided aaa, bbb, and ccc are the known subdirectories,
    # and (.+) represents ANY text that follows (i.e., any deeper
    # subdirectory structure), then $1/index.html will route to
    # the index.html file in whichever folder of the aaa|bbb|ccc list
    # that is provided: 
    RewriteRule ^(aaa|bbb|ccc)/(.+)$ $1/index.html [L]