Apache 无法忽略带NS标志的mod_重写内部重定向
我在Apache 无法忽略带NS标志的mod_重写内部重定向,apache,mod-rewrite,url-rewriting,Apache,Mod Rewrite,Url Rewriting,我在.htaccess文件中定义了两个mod_rewrite规则,一个用于将URL路径从/rwtest/source.html重写为/rwtest/target.html,另一个用于禁止直接访问/rwtest/target.html。也就是说,所有希望查看/rwtest/target.html内容的用户必须在其URL栏中输入/rwtest/source.html 我试图在禁止规则中使用NS标志来防止重写的URL也被拒绝,但是这个标志似乎没有区分第一个请求和内部重定向。似乎NS应该做这项工作,但我
.htaccess
文件中定义了两个mod_rewrite
规则,一个用于将URL路径从/rwtest/source.html
重写为/rwtest/target.html
,另一个用于禁止直接访问/rwtest/target.html
。也就是说,所有希望查看/rwtest/target.html
内容的用户必须在其URL栏中输入/rwtest/source.html
我试图在禁止规则中使用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
我在Windows7x64上运行Apache2.4.9,但在Linux上的Apache2.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
权变措施
我已经发布了一些解决方法。这方面有几个解决方法,每个都有各自的优缺点。作为免责声明,我只在
.htaccess
上下文中测试了它们
解决方法1。检查是否存在空重定向\u状态 添加一个
RewriteCond
检查%{ENV:REDIRECT_STATUS}
是否为空。如果为空,则当前请求不是内部重定向
赞成的意见
- 确定内部重定向的最直接方法
- 缺乏文件。上的页面简要介绍了此变量:
环境变量是根据重定向之前存在的环境变量创建的。它们用重定向
前缀重命名,即REDIRECT\u
变为HTTP\u USER\u AGENT
<代码>重定向\u URL、REDIRECT\u HTTP\u USER\u AGENT
和重定向\u状态
保证被设置,并且仅当其他标题在错误条件之前存在时才会被设置重定向\u查询\u字符串
我尝试了
中的所有其他RewriteCond
变量,但是除了REDIRECT\u
之外,所有变量都是空的,用于内部重定向。为什么REDIRECT\u STATUS
是REDIRECT\u STATUS
中的一个特殊选项仍然是个谜mod\u rewrite
解决办法2。停止重写规则处理,结束 与
L
标志不同,END
即使对于内部重定向也会停止重写规则
赞成的意见
- 简单。只是一个额外的旗帜
- 无法对要处理的规则和要跳过的规则进行足够的控制
解决方法3。与_请求中的原始URL匹配
%{u请求}
浏览器发送到服务器的完整HTTP请求行(例如,“GET/index.html HTTP/1.1”)
请求不会随内部重定向而更改,因此您可以与之匹配
赞成的意见
- 即使在第二轮URL处理中,也可以用于与原始URL进行匹配
欺骗
- 比其他方法复杂得多。强制使用
RewriteCond
,其中只有一条RewriteRule
就足够了
- 与大多数其他变量不同的是,匹配未取消扫描(解码)的完整URL
- 在多个
重写规则中使用不方便RewriteCond
s可以复制到每个RewriteRule
的上方,或者可以将值导出到环境变量(参见示例)。这两种方法都很老套
例子
或者,将路径导出到环境变量,并在多个重写规则中使用它
# 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
谢谢你这么完整的回答。解决了我的问题!另一个带有END
标志的“con”。。。它是Apache2.4+。检查请求一直是我选择的“变通方法”。“我在RewriteCond
中尝试了所有其他重定向
变量,但是除了重定向状态
之外,所有变量对于内部重定向都是空的。”-是的,我看到了相同的行为。在Apache 2.2文档中,它们被描述为“类似CGI的环境变量”,虽然它们似乎不可用于mod_重写,但它们可以在您的CGI/服务器端脚本中使用(并且对于错误文档非常有用,这似乎是Apache文档中唯一讨论它们的地方)。“有人能澄清一下这种行为吗?”-是的,内部重写不是子请求。(您还可以检查IS_SUBREQ
服务器变量,对于内部重写,该变量保持为“false”
)。其他模块触发子请求,例如mod_dir和mod_include(SSI)。
# 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]
# 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
# 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