如何使用htaccess(RewriteRule)重定向URL并阻止直接访问

时间:2015-02-17 12:34:13

标签: apache .htaccess mod-rewrite redirect

使用.htaccess我想透明地将文件夹“old”的请求重定向到文件夹“new”,同时阻止直接访问文件夹“new”:

期望的结果:

http://example.com/old/ ... - >将显示“新”中的内容(浏览器中没有URL更改!) http://example.com/new/ ... - >无法访问

这是我在.htaccess中的代码(第一行在这里,因为几个域共享相同的根文件夹):

RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^old(.*)$ new$1 [L]
RewriteRule ^new(.*)$ - [F]

嗯,接下来会发生因为第二行中的替换而引发的3d线。我确信标志“L”会阻止这种情况发生(处理结束),但似乎情况并非如此。

您是否有任何建议需要做什么(我尝试使用重写日志进行调试,但没有成功)?

我做了一些日志记录,发现了以下内容:

[rid#d0ac98/initial] (3) [per-dir C:/www/example/] add path info postfix: C:/www/example/new -> C:/www/example/new/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/new/ -> new/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] applying pattern '^new(.*)$' to uri 'new/'
[rid#d0ac98/initial] (4) RewriteCond: input='localhost' pattern='^example\.com$' => not-matched
[rid#d0ac98/initial] (4) RewriteCond: input='localhost' pattern='^localhost$' => matched
[rid#d0ac98/initial] (2) [per-dir C:/www/example/] rewrite new/ -> old/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] add per-dir prefix: old/ -> C:/www/example/old/
[rid#d0ac98/initial] (2) [per-dir C:/www/example/] strip document_root prefix: C:/www/example/old/ -> /example/old/
[rid#d0ac98/initial] (1) [per-dir C:/www/example/] internal redirect with /example/old/ [INTERNAL REDIRECT]
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/old/ -> old/
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] applying pattern '^new(.*)$' to uri 'old/'
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/old/ -> old/
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] applying pattern '^old(.*)$' to uri 'old/'
[rid#d217a8/initial/redir#1] (2) forcing 'C:/www/example/old/' to be forbidden

这似乎是内部重定向,导致“禁止”结果。实际上,文档提到了它:

因此,如果您在其中一个上下文中使用RewriteRule指令,则必须采取明确的步骤来避免规则循环,并且不要仅依靠[L]标志来终止一系列的执行规则,如下所示。另一个标志[END]不仅可以用于终止当前轮次的重写处理,还可以防止在每个目录(htaccess)上下文中发生任何后续重写处理。这不适用于外部重定向产生的新请求......

所以我想在我的例子中,错误是由于我使用“L”标志而不是“END”标志这一事实?

我找到了另一种解决方案(此处插入第3行):

RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^old(.*)$ new$1 [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^new(.*)$ - [F]

只有在没有内部重定向的情况下才会执行第4行。

1 个答案:

答案 0 :(得分:0)

您可以使用:

RewriteEngine On

# if directly requesting /new then block it
RewriteCond %{THE_REQUEST} \s/+new(/\S*)?\s [NC]
RewriteRule ^ - [F]

# forward /old/abc to /new/abc
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^old(/.*)?$ new$1 [L,NC]

我们在第一条规则中使用了THE_REQUESTTHE_REQUEST变量表示Apache从您的浏览器收到的原始请求,在执行某些重写规则后不会被覆盖。另一方面,REQUEST_URI在其他重写规则之后更改其值。

出于同样的原因,您的规则RewriteRule ^new(.*)$ - [F]甚至会阻止您的请求来自/old/,因为第一条规则会将URI更改为/new/