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>
效果应该是这样
/app
搜索文件时转到 -> /some-site/map-app
- 如果失败(因为它通常是 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
一些例子和期望的结果:
/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 逻辑未包含在 post 中,但包含示例以防它更改潜在答案)
第一次重写后,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
匹配,因为斜线是可选的,我确定这不是本意。大概你想匹配 app
或 app/
或 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 (次要重复内容问题).
我也想知道目录检查是否真的有必要?
我很确定问题是 %{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>
效果应该是这样
/app
搜索文件时转到 ->/some-site/map-app
- 如果失败(因为它通常是 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
一些例子和期望的结果:
/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 逻辑未包含在 post 中,但包含示例以防它更改潜在答案)
第一次重写后,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
匹配,因为斜线是可选的,我确定这不是本意。大概你想匹配 app
或 app/
或 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 (次要重复内容问题).
我也想知道目录检查是否真的有必要?