I have an HTTP-API, written in PHP and I redirect all calls to my index.php where a (Slim-)router does the rest. That works.
My redirection in .htaccess
looks like:
Options +FollowSymLinks
Options -Indexes
RewriteEngine on
RewriteRule ^ index.php [QSA,L]
There is only one problem: If one endpoint is named identically with an existing folder, strange things happen. That’s the case when I create an endpoint [PUT] /test
, while there is also a folder called test
, containing unit tests.
This is what is happening:
- If I call
[PUT] /test
with preflight I get no response at all for the OPTIONS call which leads my app to fail. That’s the real problem case, since I need CORS. - If I call it without preflight and PUT I get 301 forwarding on the same endpoint.
- If I call it without preflight and POST I get 301 forwarding on the same endpoint, but with GET?!
I guess I have to change something in .htaccess
to make it ignore the existence of the folder, but what?
How to reproduce
Have an Apache server and create directory as following:
- /target
- /target/.htaccess
Options +FollowSymLinks
Options -Indexes
RewriteEngine on
RewriteRule ^ index.php [QSA,L]
- /target/index.php
<?php echo $_SERVER['REQUEST_URI'];
-
/target/subfolder
-
/testscript.html
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>test</title>
<style>
div {margin: 0.5em;}
.error { background: rgba(255, 0, 0, 0.3);}
.success { background: rgba(0, 255, 0, 0.3);}
</style>
</head>
<body>
<script>
const call = (url) => {
fetch(url, {
redirect: "manual",
method: "POST"
}).then(async response => {
const className = (response.redirected) ? 'success' : 'error';
const content = await response.text();
document.querySelector('body').innerHTML += `<div class='${className}'>${url}<hr /><b>[${response.status}]</b> ${content}</div>`;
});
};
call('target/endpoint');
call('target/subfolder');
</script>
</body>
</html>
Open http://localhost/
…testscript.html
in browser and see: the call on target/subfolder
changed it’s method. Also when you look at network tab in browser console you can see, that there was 301 forwarding. Why? And more important: How can I circumvent this. My desired behavior is a rewrite without any changing in terms of method to the index.php
in disregard of the existence of a folder with that name. In other words: The same what happens when I call target/endpoint
for target/subfolder
.
I know about -d
(and -f
) naturally, but that can be used – as far as I know – to to control behavior depending if file or folder exists – so I would assume without these flags the existence of the directory should not play any role, but it does, apparently.
2
Answers
With the help of @anuhava I found the right way to solve this. His answer alone did not help, but led me to this thread, and I found out the solution war actually to disable automatic trailing slash in
.htaccess
:I had the additional (not mentioned before) requirement to define a exception directory which should be accessible directly. To make this possible as well, I needed the rule of @anuhava and I endet up with this
.htaccess
:So first the reason of
301
:/target/subfolder
which actually points to an directory on your site.mod_dir
module of Apache comes into action and sends a301
redirect by making it/target/subfolder/
. This is done for security reasons to avoid your directory content being exposed on the web.To fix, you can just use
call
with a trailing slash everywhere it points to a directory:But this cumbersome because front end developers won’t always know these specific cases.
You can use a generic rule in your .htaccess or Apache config to add this trailing slash:
Make sure this rule is just below
RewriteEngine On
line and before your existing rules.