无法忽略带有NS标志的mod_rewrite内部重定向

mxx*_*xxk 10 apache mod-rewrite url-rewriting

我已经定义了一对夫妇mod_rewrite在一个规则.htaccess文件,一个从重写URL路径/rwtest/source.html/rwtest/target.html,而另一个禁止直接访问/rwtest/target.html.也就是说,所有希望查看内容的用户都/rwtest/target.html必须/rwtest/source.html在其URL栏中输入.

我试图NS在禁止规则中使用该标志以防止重写的URL被拒绝,但看起来这个标志不区分第一个请求和内部重定向.似乎NS应该做这个工作,但我确信我误解了一些事情.

有人可以澄清这种行为吗?究竟是什么让这个内部重定向不是NS标志可以忽略的内部子请求?

细节:

这是我的完整.htaccess档案:

Options +FollowSymLinks -Multiviews

RewriteEngine on
RewriteBase /rwtest

# Forbid rule. Prohibit direct access to target.html. Note the NS flag.
RewriteRule ^target.html$ - [F,NS]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html
Run Code Online (Sandbox Code Playgroud)

我在Windows 7 x64上运行Apache 2.4.9,但我在Linux上观察到Apache 2.4.3上的类似行为.这是请求的日志输出/rwtest/source.html.

[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/source.html -> source.html
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^target.html$' to uri 'source.html'
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/source.html -> source.html
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^source.html$' to uri 'source.html'
[rewrite:trace2] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] rewrite 'source.html' -> 'target.html'
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] add per-dir prefix: target.html -> C:/Apache24/htdocs/rwtest/target.html
[rewrite:trace2] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] trying to replace prefix C:/Apache24/htdocs/rwtest/ with /rwtest
[rewrite:trace5] [rid#20b6200/initial] strip matching prefix: C:/Apache24/htdocs/rwtest/target.html -> target.html
[rewrite:trace4] [rid#20b6200/initial] add subst prefix: target.html -> /rwtest/target.html
[rewrite:trace1] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] internal redirect with /rwtest/target.html [INTERNAL REDIRECT]
[rewrite:trace3] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/target.html -> target.html
[rewrite:trace3] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^target.html$' to uri 'target.html'
[rewrite:trace2] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] forcing responsecode 403 for C:/Apache24/htdocs/rwtest/target.html
Run Code Online (Sandbox Code Playgroud)

解决方法

我在下面发布了一些解决方法.

mxx*_*xxk 11

有几种解决方法,每种都有它们的优点和缺点.作为免责声明,我只是在.htaccess上下文中测试它们.


解决方法1.检查空REDIRECT_STATUS

添加RewriteCond检查以查看是否%{ENV:REDIRECT_STATUS}为空.如果为空,则当前请求不是内部重定向.

优点

  • 最直接的方法来确定内部重定向.

缺点

  • 缺乏文件.自定义错误响应页面简要提到了此变量:

    REDIRECT_环境变量是从重定向之前存在的环境变量创建的.它们用REDIRECT_前缀重命名,即HTTP_USER_AGENT成为REDIRECT_HTTP_USER_AGENT.REDIRECT_URL,REDIRECT_STATUS并且REDIRECT_QUERY_STRING保证被设置,并且只有在错误条件之前存在其他标题时才设置其他标题.

    我已经尝试了所有其他REDIRECT_变量RewriteCond,但除了REDIRECT_STATUS内部重定向之外所有变量都是空的.为什么REDIRECT_STATUS特殊的一个mod_rewrite仍然是个谜.

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^target.html$ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html
Run Code Online (Sandbox Code Playgroud)

此方法的学分转到URL重写:内部服务器错误.


解决方法2.使用END暂停重写规则处理

L标志不同,END即使对于内部重定向,也会暂停重写规则.

优点

  • 简单.只是一个额外的旗帜.

缺点

  • 不能让您充分控制要处理的规则和要跳过的规则.

# Forbid rule. Prohibit direct access to target.html.
RewriteRule ^target.html$ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html [END]
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅END标志.


解决方法3.与THE_REQUEST中的原始URL匹配

%{THE_REQUEST}

浏览器向服务器发送的完整HTTP请求行(例如,"GET /index.html HTTP/1.1").

THE_REQUEST 内部重定向不会更改,因此您可以匹配它.

优点

  • 即使在第二轮URL处理中,也可用于匹配原始URL.

缺点

  • 比其他方法复杂得多.强制使用RewriteCond只有一个RewriteRule就足够的地方.

  • 与大多数其他变量不同,匹配尚未转义(解码)的完整URL.

  • 不方便在多个RewriteRules中使用.RewriteConds可以复制到每个上面,RewriteRule或者可以将值导出到环境变量中(参见示例).两种黑客替代方案.

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)"  # extract path from request line
RewriteCond %1 ^/rwtest/target.html$
RewriteRule ^ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html
Run Code Online (Sandbox Code Playgroud)

或者,将路径导出到环境变量并在多个RewriteRules中使用它.

# Extract the original URL and save it to ORIG_URL.
RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)"  # extract path from request line
RewriteRule ^ - [E=ORIG_URL:%1]

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{ENV:ORIG_URL} ^/rwtest/target.html$
RewriteRule ^ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteCond %{ENV:ORIG_URL} ^/rwtest/source.html$
RewriteRule ^ target.html
Run Code Online (Sandbox Code Playgroud)

  • 另一个带有"END"标志的"con"......它是Apache 2.4+.检查"THE_REQUEST"一直是我选择的"解决方法". (2认同)