I have the following directory structure where /root
acts as my root directory despite being nested among any number of subdirectories:
- example.com/dir1/root
- client/build
- api
When the user navigates to example.com/dir1/root/
, I'd like all requests to be redirected to example.com/dir1/root/client/build/
but without changing the URL, as if the build/
directory contents were inside root/
.
Additionally, I'd like all requests like example.com/dir1/root/api/*
to be redirected to example.com/dir1/root/api/
. Again, without changing the URL.
This is my current attempt, given my little understanding of how .htaccess works:
RewriteEngine on
# If an existing asset or directory is requested go to it as it is.
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# Redirect all requests under /api/ to the API.
RewriteCond %{REQUEST_URI} ^/api/
RewriteRule ^ api/index.php [L]
# If the requested resource doesn't exist, use index.html (html5mode)
RewriteRule ^ client/build/index.html [L]
Note: I've searched but not found any answers for this specific scenario, and given my poor htaccess knowledge, I'm unable to cobble existing answers together very well.
CodePudding user response:
index.html
is requesting resources likeexample.com/dir1/root/assets/style.css
when this resides in/root/client/build/assets/
. Essentially, I want/root/
to behave as if it's actually/root/client/build
, except in the instance/root/api/
is requested.
I would implement this as 2 separate .htaccess
files. One in the "root" directory (ie. /dir1/root/.htaccess
) that handles the "api" requests and rewrites everything else to client/build
(ie. a "false root"). And another .htaccess
file in /dir1/root/client/build/.htaccess
that handles just the routing within your app frontend.
For example:
# /dir1/root/.htaccess
RewriteEngine On
# Rewrite all requests under /api/ to the API handler "index.php"
RewriteRule ^api/(?!index\.php) api/index.php [L]
# Rewrite everything else to the "client/build/" subdirectory
RewriteRule (.*) client/build/$1 [L]
And...
# /dir1/root/client/build/.htaccess
DirectoryIndex index.html
RewriteEngine On
# Front-controller
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
The presence of the .htaccess
file (containing mod_rewrite directives) in the subdirectory also serves to prevent a rewrite-loop, since it prevents directives in the parent .htaccess
being re-processed (and rewriting the request back to client/build/...
again and again).
A quick look at your existing rules...
# If an existing asset or directory is requested go to it as it is. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d RewriteRule ^ - [L] # Redirect all requests under /api/ to the API. RewriteCond %{REQUEST_URI} ^/api/ RewriteRule ^ api/index.php [L] # If the requested resource doesn't exist, use index.html (html5mode) RewriteRule ^ client/build/index.html [L]
Issues with your existing rules:
Since the first rule prevents any requests that map to files or directories being processed, it will also prevent requests for
/dir1/root/
itself (which is a directory) being rewritten to/dir1/root/client/build/index.html
.The condition
RewriteCond %{REQUEST_URI} ^/api/
will never be successful since theREQUEST_URI
server variable contains the root-relative URL-path, ie./dir1/root/api/
.Since everything else is rewritten from the "root" to
client/build/index.html
, the static assets that also reside inclient/build/
are not rewritten correctly (they are rewritten toindex.html
so presumably result in an unexpected response).You can't perform the filesystem checks in the "root"
.htaccess
file, since the static assets that relate toindex.html
only "exist" after they have been rewritten.