【问题标题】:Redirect [R=301] ends next iterations in .htaccess?重定向 [R=301] 在 .htaccess 中结束下一次迭代?
【发布时间】:2020-08-13 16:14:03
【问题描述】:

我有这个简单的 .htaccess:

RewriteEngine On

RewriteBase /

RewriteRule ^foo3$ foo2
RewriteRule ^foo2$ foo1
RewriteRule ^foo1$ index.php

当我输入 url https://localhost/foo3 时,它会跟随 de rewrite "chain" 并以 index.php 结尾。没关系。

但是对于这个.htaccess:

RewriteEngine On

RewriteBase /

RewriteRule ^foo3$ foo2 [R=301]
RewriteRule ^foo2$ foo1
RewriteRule ^foo1$ index.php

我希望它无论如何都会级联到 index.php(忽略重定向),但浏览器首先将 301 重定向到 https://localhost/foo2(浏览器反映该 url),然后 .htaccess 从那里“继续”到索引.php。

在这种情况下,R=301 的行为是否类似于 [END] 指令?

【问题讨论】:

    标签: regex apache .htaccess mod-rewrite


    【解决方案1】:

    R=301 在这种情况下是否像 [END] 指令一样起作用?

    不,END 无效,但 L(最后一个)有效。请理解END 的行为与L 不同。

    因此 Apache 向浏览器发送301,浏览器进行完全重定向,然后再次向 Web 服务器发送 /foo2,然后执行第 2 条和第 3 条规则。


    更新:

    感谢下面@MrWhite 的评论,我已经运行了这个测试,同时将重写日志保存在trace4

    配置启用重写日志记录:

    LogLevel info rewrite:trace4
    

    以下是我的 Apache 错误日志中的其他日志。请注意,我的本地主机名是localhost,我的DocumentRoot/www/root

    步骤:应用规则#1,URI是/foo3

    strip per-dir prefix: /www/root/foo3 -> foo3
    applying pattern '^foo3$' to uri 'foo3'
    rewrite 'foo3' -> 'foo2'
    add per-dir prefix: foo2 -> /www/root/foo2
    explicitly forcing redirect with http://localhost/www/root/foo2
    

    步骤:应用规则#2,URI是http://localhost/www/root/foo2(注意你的RewriteBase /还没有生效):

    applying pattern '^foo2$' to uri 'http://localhost/www/root/foo2'
    

    步骤:应用规则#3,URI是http://localhost/www/root/foo2

    applying pattern '^foo1$' to uri 'http://localhost/www/root/foo2'
    

    步骤:通过使用您的RewriteBase 值剥离DocumentRoot 来应用外部重定向301

    trying to replace prefix /www/root/ with /
    add subst prefix: foo2 -> foo2
    escaping http://localhost/foo2 for redirect
    redirect to http://localhost/foo2 [REDIRECT/301]
    

    步骤:应用规则#1,URI是/foo2

    strip per-dir prefix: /www/root/foo2 -> foo2
    applying pattern '^foo3$' to uri 'foo2'
    

    步骤:应用规则#2,URI是/foo2

    strip per-dir prefix: /www/root/foo2 -> foo2
    applying pattern '^foo2$' to uri 'foo2'
    rewrite 'foo2' -> 'foo1'
    

    步骤:应用规则#3,URI是/foo1

    add per-dir prefix: foo1 -> /www/root/foo1
    strip per-dir prefix: /www/root/foo1 -> foo1
    applying pattern '^foo1$' to uri 'foo1'
    rewrite 'foo1' -> 'index.php'
    

    步骤:内部重写为/index.php

    add per-dir prefix: index.php -> /www/root/index.php
    trying to replace prefix /www/root/ with /
    add subst prefix: index.php -> /index.php
    internal redirect with /index.php [INTERNAL REDIRECT]
    

    步骤:应用规则#1,URI是/index.php

    strip per-dir prefix: /www/root/index.php -> index.php
    applying pattern '^foo3$' to uri 'index.php'
    

    步骤:应用规则#2,URI是/index.php

    strip per-dir prefix: /www/root/index.php -> index.php
    applying pattern '^foo2$' to uri 'index.php'
    

    步骤:应用规则#3,URI是/index.php

    strip per-dir prefix: /www/root/index.php -> index.php
    applying pattern '^foo1$' to uri 'index.php'
    

    步骤:停止规则处理,URI为/index.php

    pass through /www/root/index.php
    

    我在上面添加了详细的跟踪记录和我的step 评论,以说明L 是一个副作用,其中规则处理没有完全停止。然而,mod_rewrite 引擎试图在 无效 的 URI 上应用剩余规则,即 http://localhost/www/root/foo2 这些规则不会执行,结果将是完全重定向。

    【讨论】:

    • 但是为什么要发送 301 呢?为什么它在第一次迭代中不处理第二条和第三条规则,“覆盖”第一条规则(如第一个示例)?
    • 如果我正确理解 .ht 执行,当遇到L 标志并发生重写时,.ht 从头开始​​重新运行重写为“请求的uri”。如果这是正确的,当R=301(加上隐含的L)被评估时,不再处理规则,第二次迭代应该以foo2作为输入开始。在该迭代中,将应用第二条规则,然后是第一条规则(第二条规则中没有L)。我们到达 EOF 并且发生了重写,因此第三次迭代以 index.php 作为输入开始。没有重写发生,所以index.php 应该是要获取的资源。这准确吗?
    • 你说得真好,绝对正确。
    • 是的,没错。由于R 的完全重定向是首次运行的结果,因此 apache 必须将该状态发送回浏览器。当浏览器使用新 URL 发送下一个请求时,即/foo2,它会再次从顶部处理 .htaccess。
    • “当你使用 R 标志时,L 是隐含的” - 这并不完全正确。 L 标志仅适用于非 3xx 响应代码。在上面的例子中,处理 does 继续,除了下面的规则根本不匹配,因为R=301 标志导致重写引擎构造一个绝对 URL(排序),然后传递给下一条规则。删除第二条规则上的起始锚点(^),它确实匹配,最终导致一些格式错误的响应......它在内部重写为index.php,但发送301响应代码并且没有Location标头(所以没有重定向)。
    猜你喜欢
    • 1970-01-01
    • 2011-05-01
    • 2011-01-03
    • 2012-03-10
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多