Apache RewriteCond %{REQUEST_FILENAME} !-f 在文件存在时失败

Apache RewriteCond %{REQUEST_FILENAME} !-f failing when file exists

我很确定问题是 %{REQUEST_FILENAME} 没有引用更改后的 URI,而是引用了请求的 URI。

我有一些这样的代码:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule app/?(.*)$ /some-site/map-app/ [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>

效果应该是这样

  1. /app 搜索文件时转到 -> /some-site/map-app
  2. 如果失败(因为它通常是 SPA),它会转到 /some-site/map-app/index.html

出于某种原因,它正在重写 index.html 回退的每条路径。这意味着 #1 的发生足以满足 RewriteRule 条件,但由于某种原因 RewriteCond 不起作用。

如果我删除 #2 的逻辑,文件可以正常解析,所以问题不在于它生成的路径有问题。

我已阅读有关“RewriteCond Specials”的文档 (https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html)

为什么这两个在第二个逻辑块中存在的路径没有失败 - 并且已经由第一个逻辑块产生 - ?

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

一些例子和期望的结果:

第一次重写后,REQUEST_FILENAME 服务器变量仅包含重写的 URL 路径(例如 /some-site/map-app/foo),而不是重写的绝对文件系统路径 URL 将映射到。因此,在此阶段尝试对 REQUEST_FILENAME 进行文件系统检查总是会失败。

需要将请求重新映射回文件系统,以便 REQUEST_FILENAME 变量更新为绝对文件系统路径。这仅发生在重写引擎开始时(以及每次通过之前)。

您可以通过简单地在第一条规则中包含 L (last) 标志来强制重写引擎重新开始。这结束了当前一轮的处理,并将重写的 URL 传回重写引擎,此时重写的 URL 被重新映射到文件系统并更新了 REQUEST_FILENAME

或者,不要在第二条规则中使用 REQUEST_FILENAME,而是从 DOCUMENT_ROOT 手动构造绝对文件名并重写 URL-path.

例如:

# If the previously rewritten URL does not map to a file (or directory)...
RewriteCond %{DOCUMENT_ROOT}/[=10=] !-f
RewriteCond %{DOCUMENT_ROOT}/[=10=] !-d
RewriteRule ^some-site/map-app(?:$|/(.*)) /some-site/map-app/index.html [NC,L]

其中 [=21=] 是对 RewriteRule 模式 匹配的整个 URL 路径的反向引用。

您现有的正则表达式(RewriteRule 模式)存在问题。正则表达式 app/?(.*)$appanything 匹配,因为斜线是可选的,我确定这不是本意。大概你想匹配 appapp/app/<something>?这也应该锚定到 URL 路径的开头,否则,它也会匹配 /some-site/map-app/<something>(用于第二条规则)。这同样适用于第二条规则(以上更新)。

因此,请尝试以下操作(如果不在第一条规则中使用 L 标志):

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^app(?:$|/(.*)) /some-site/map-app/ [NC]

# If the previously rewritten URL does not map to a file (or directory)...
RewriteCond %{DOCUMENT_ROOT}/[=11=] !-f
RewriteCond %{DOCUMENT_ROOT}/[=11=] !-d
RewriteRule ^some-site/map-app(?:$|/(.*)) /some-site/map-app/index.html [NC,L]

不需要 <IfModule> 包装器或重复 RewriteEngine 指令。 QSA(查询字符串附加)标志也是多余的,因为这是默认操作。我也会谨慎使用 NC 标志(在内部重写时),因为这允许 /app/APP 映射到相同的 URL (次要重复内容问题).

我也想知道目录检查是否真的有必要?