I'm pretty sure the issue is that %{REQUEST_FILENAME}
does not reference a URI as it as been changed, but instead as it has been requested.
I have some code like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule app/?(.*)$ /some-site/map-app/$1 [NC,QSA]
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule some-site/map-app/?(.*)$ /some-site/map-app/index.html [NC,L,QSA]
</IfModule>
The effect is supposed to be that
/app
goes to ->/some-site/map-app
when searching for files- if that fails (as it will often because it's an SPA), it goes to
/some-site/map-app/index.html
For some reason it's rewriting every path to the index.html
fallback. This means that #1 is occurring enough to meet the RewriteRule
condition, but for some reason the RewriteCond
are not working.
If I remove the logic for #2, the files resolve fine so the issue is not that the paths it produces are bad.
I've read the docs on "RewriteCond Specials" (https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html)
Why are these two not failing for paths that exist -- and have been produced by the first logic block -- within the second logic block?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Some examples and the desired outcome:
/app/
->/some-site/map-app/index.html
/app/map/id-3
->/some-site/map-app/index.html
/app/app.js
->/some-site/map-app/app.js
/app/assets/img/1.png
->/some-site/assets/img/1.png
(RewriteEngine logic not included in post, but example included in case it changes potential answers)
CodePudding user response:
Immediately after the first rewrite, the REQUEST_FILENAME
server variable contains the rewritten URL-path only (eg. /some-site/map-app/foo
), not the absolute filesystem path that the rewritten URL would map to. So, attempting to do a filesystem check on REQUEST_FILENAME
at this stage will always fail.
The request needs to be remapped back to the filesystem for the REQUEST_FILENAME
variable to be updated to the absolute filesystem path. This only occurs at the start of (and before each pass through) the rewriting engine.
You can force the rewriting engine to start over by simply including the L
(last
) flag on the first rule. This ends the current round of processing and passes the rewritten URL back into the rewrite engine, at which point the rewritten URL is remapped to the filesystem and REQUEST_FILENAME
is updated.
Alternatively, don't use REQUEST_FILENAME
in the second rule and instead manually construct the absolute filename from the DOCUMENT_ROOT
and rewritten URL-path.
For example:
# If the previously rewritten URL does not map to a file (or directory)...
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteCond %{DOCUMENT_ROOT}/$0 !-d
RewriteRule ^some-site/map-app(?:$|/(.*)) /some-site/map-app/index.html [NC,L]
Where $0
is a backreference to the entire URL-path that the RewriteRule
pattern would match.
There is an issue with your existing regex (RewriteRule
pattern). The regex app/?(.*)$
matches appanything
since the slash is optional, which I'm sure is not the intention. Presumably you want to match app
or app/
or app/<something>
? This should also be anchored to the start of the URL-path, otherwise, it will also match /some-site/map-app/<something>
(which is intended for the second rule). The same applies to the second rule (updated above).
So, try the following instead (if not using the L
flag on the first rule):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^app(?:$|/(.*)) /some-site/map-app/$1 [NC]
# If the previously rewritten URL does not map to a file (or directory)...
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteCond %{DOCUMENT_ROOT}/$0 !-d
RewriteRule ^some-site/map-app(?:$|/(.*)) /some-site/map-app/index.html [NC,L]
No need for the <IfModule>
wrapper or repeating the RewriteEngine
directive. The QSA
(Query String Append) flags were also superfluous, since this is the default action. I would also be wary of using the NC
flag (on an internal rewrite) since this permits both /app
and /APP
to map to the same URL (minor duplicate content issue).
I also wonder whether the directory checks are really necessary?