【问题标题】:Apache RewriteCond %{REQUEST_FILENAME} !-f failing when file existsApache RewriteCond %{REQUEST_FILENAME} !-f 文件存在时失败
【发布时间】:2021-12-22 11:03:39
【问题描述】:

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

我有一些这样的代码:

<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>

效果应该是这样的

  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

一些例子和期望的结果:

  • /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 逻辑未包含在帖子中,但包含示例以防它更改潜在答案)

【问题讨论】:

  • 你在哪里使用这些指令?
  • 在 public_html 文件夹根目录的 .htaccess 文件中
  • 您是否收到对/some-site/map-app 的直接请求?还是外部请求总是进入/app
  • 我花了大约 15 分钟阅读文档并思考这个问题,然后得出结论认为这个需要@MrWhite 现在他在上面,我只是坐在这里像体育赛事一样观看.
  • 另外,根据您的第一条规则,您可以重写到目录而不是文件吗? (虽然这看起来不太可能?除了下一个明确检查这个?)

标签: apache mod-rewrite


【解决方案1】:

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

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

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

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

例如:

# 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]

其中$0 是对RewriteRule 模式 将匹配的整个URL 路径的反向引用。

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

因此,请尝试以下方法(如果第一条规则中没有使用 L 标志):

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]

不需要&lt;IfModule&gt; 包装器或重复RewriteEngine 指令。 QSA(查询字符串追加)标志也是多余的,因为这是默认操作。我也会对使用NC 标志(在内部重写时)保持警惕,因为这允许/app/APP 映射到相同的URL(轻微的重复内容问题)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多