我在mod_rewrite
文件中定义了一些.htaccess
规则,一个用于重写从/rwtest/source.html
到/rwtest/target.html
的网址路径,另一个规则禁止直接访问{ {1}}。也就是说,希望查看/rwtest/target.html
内容的所有用户都必须在其网址栏中输入/rwtest/target.html
。
我试图在禁止规则中使用/rwtest/source.html
标志来防止重写的URL被拒绝,但看起来这个标志不区分第一个请求和内部重定向。似乎NS
应该完成这项工作,但我确定我误解了一些事情。
有人可以澄清这种行为吗?究竟是什么使这个内部重定向不是NS
标志可以忽略的内部子请求?
这是我的完整NS
文件:
.htaccess
我在Windows 7 x64上运行Apache 2.4.9,但我在Linux上观察到Apache 2.4.3上的类似行为。这是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
请求的日志输出。
/rwtest/source.html
我发布了一些解决方法below。
答案 0 :(得分:11)
有几种解决方法,每种都有其优缺点。作为免责声明,我只在.htaccess
上下文中对它们进行了测试。
添加RewriteCond
检查以查看%{ENV:REDIRECT_STATUS}
是否为空。如果它为空,则当前请求不是内部重定向。
缺乏文档。 Custom Error Responses上的页面简要提到了这个变量:
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
这种方法的功劳归到URL rewrite : internal server error。
与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]
有关详细信息,请参阅END flag。
%{THE_REQUEST}
浏览器向服务器发送的完整HTTP请求行(例如,“GET /index.html HTTP / 1.1”)。
THE_REQUEST
不会因内部重定向而发生变化,因此您可以对其进行匹配。
比其他方法复杂得多。强制使用RewriteCond
只需一个RewriteRule
即可。
与未转义(解码)的完整网址匹配,与大多数其他变数不同。
在多个RewriteRule
中使用不方便。可以在每RewriteCond
之上复制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
或者,将路径导出到环境变量并在多个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