[英]mod_rewrite tries to redirect if folder exists
I have an HTTP-API, written in PHP and I redirect all calls to my index.php where a (Slim-)router does the rest.我有一个用 PHP 编写的 HTTP-API,我将所有调用重定向到我的 index.php,一个(Slim-)路由器完成其余的工作。 That works.那个有效。
My redirection in .htaccess
looks like:我在.htaccess
重定向如下所示:
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.当我创建一个端点[PUT] /test
时就是这种情况,同时还有一个名为test
的文件夹,其中包含单元测试。
This is what is happening:这是正在发生的事情:
[PUT] /test
with preflight I get no response at all for the OPTIONS call which leads my app to fail.如果我在预检时调用[PUT] /test
,对于导致我的应用程序失败的 OPTIONS 调用,我根本没有任何响应。 That's the real problem case, since I need CORS.这是真正的问题案例,因为我需要 CORS。 I guess I have to change something in .htaccess
to make it ignore the existence of the folder, but what?我想我必须更改.htaccess
某些内容以使其忽略文件夹的存在,但是什么?
How to reproduce如何繁殖
Have an Apache server and create directory as following:有一个 Apache 服务器并创建目录如下:
Options +FollowSymLinks
Options -Indexes
RewriteEngine on
RewriteRule ^ index.php [QSA,L]
<?php echo $_SERVER['REQUEST_URI'];
/target/subfolder /目标/子文件夹
/testscript.html /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.在浏览器中打开http://localhost/
... testscript.html
并看到: target/subfolder
上的调用改变了它的方法。 Also when you look at network tab in browser console you can see, that there was 301 forwarding.此外,当您查看浏览器控制台中的网络选项卡时,您会看到有 301 转发。 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.我想要的行为是重写而不改变index.php
的方法,而不管是否存在具有该名称的文件夹。 In other words: The same what happens when I call target/endpoint
for target/subfolder
.换句话说:当我为target/subfolder
调用target/endpoint
时会发生同样的情况。
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.我自然知道-d
(和-f
),但是可以使用 - 据我所知 - 根据文件或文件夹是否存在来控制行为 - 所以我假设没有这些标志,目录的存在不应该播放任何角色,但显然确实如此。
So first the reason of 301
:所以首先是301
的原因:
/target/subfolder
which actually points to an directory on your site.您正在请求一个 URI /target/subfolder
,它实际上指向您网站上的一个目录。mod_dir
module of Apache comes into action and sends a 301
redirect by making it /target/subfolder/
. Apache 的mod_dir
模块生效并通过将其设置为/target/subfolder/
来发送301
重定向。 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:要修复,您可以在指向目录的任何地方使用带有斜杠的call
:
call('target/subfolder/');
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:您可以在 .htaccess 或 Apache 配置中使用通用规则来添加此尾部斜杠:
# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]
Make sure this rule is just below RewriteEngine On
line and before your existing rules.确保此规则位于RewriteEngine On
线下方且位于现有规则之前。
With the help of @anuhava I found the right way to solve this.在@anuhava 的帮助下,我找到了解决这个问题的正确方法。 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
:单独他的回答没有帮助,但将我带到了这个线程,我发现了解决方案战争实际上禁用了.htaccess
自动尾随斜杠:
DirectorySlash Off
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
:为了使这成为可能,我需要@anuhava 的规则,我最终得到了这个.htaccess
:
DirectorySlash Off
Options +FollowSymLinks
Options -Indexes
RewriteEngine on
# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L]
# rewrite all calls excpet for exception_dir to index.php
RewriteCond %{REQUEST_URI} !/target/exception_dir
RewriteRule ^ index.php [QSA,L]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.