.htaccess - 如何让 RewriteRule (.htaccess) 的 [L] 标志真正起作用?

标签 .htaccess mod-rewrite

致新人:在尝试全面描述我的问题并表达我的问题时,我制作了大量文本。如果你不想阅读整篇文章,我对(阅读“证明”)的观察[L]标志不起作用的误解,它全部来自于其他观察 部分。我的答案以及给定问题的解决方案中描述了为什么我误解了明显的行为。
设置

我的 .htaccess 文件中有以下代码:

# disallow directory indexing
Options -Indexes

# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on

# allow access to robots file
RewriteRule ^robots.txt$ robots.txt [NC,L]

# mangle core request handler address
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]

# mangle web file adresses (move them to application root folder)
# application root folder serves as application GUI address
RewriteRule ^$ web/index.html [L]
# allow access to images
RewriteRule ^(images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]
# allow access to stylesheets
RewriteRule ^(css/.+\.css)$ web/$1 [NC,L]
# allow access to javascript
RewriteRule ^(js/.+\.js)$ web/$1 [NC,L]
# allow access to library scripts, styles and images
RewriteRule ^(lib/js/.+\.js)$ web/$1 [NC,L]
RewriteRule ^(lib/css/.+\.css)$ web/$1 [NC,L]
RewriteRule ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]

# redirect all other requests to application address
# RewriteRule ^(.*)$ /foo/ [R]
我的 Web 应用程序(及其 .htaccess 文件)位于 foo DOCUMENT_ROOT 的子文件夹(从浏览器访问为 http://localhost/foo/ )。它的 PHP 核心部分位于 foo/core和 JavaScript GUI 部分位于 foo/web .从上面的代码可以看出,我只想允许访问处理来自 GUI 的所有请求的单核脚本和“安全”Web 文件,并将所有其他请求重定向到基本应用程序地址(最后评论的指令)。

问题

行为
在我通过取消对最后一个重定向指令的注释来尝试最后一部分之前,它一直有效。 如果我评论更多行,相应的页面部分将停止工作,等等。
但是,当我取消注释最后一行时,只有在所有先前规则的匹配失败时才应执行该行(至少这是我的理解),页面进入重定向循环(Firefox 会抛出类似“此页面未正确重定向的错误页面” "),因为它重定向到 http://localhost/foo/一次又一次,永远。
问题
我不明白的是这个规则的处理:RewriteRule ^$ web/index.html [L] ,
特别是 [L]旗帜。 国旗显然对我不起作用。 当最后一行被注释时,它正确重定向,但是当我取消注释它时,它总是被处理,即使重写应该在 [L] 标志上停止。有人有任何想法吗?
另外,在旁注中,我很高兴知道为什么我的以下修复尝试也不起作用:
RewriteEngine on
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]
RewriteRule ^(.*)$ web/$1 [L]
RewriteRule ^.*$ /foo/ [L]
这实际上根本不起作用。即使我删除了最后一行,它仍然无法正确重定向任何内容。如果在第二个示例中不起作用,重定向在第一个示例中如何工作?
如果有人知道实际调试这些指令的任何方法,这对我来说也有很​​大的好处。我在这上面花了几个小时,甚至没有丝毫线索可能是什么问题。

其他观察

在尝试了 bbadour 给出的建议后(不是我以前没有尝试过,但现在我有了第二个意见,我又试了一次)并且没有奏效,我想出了以下观察结果。通过将最后一行重写为:
RewriteRule ^(.*)$ /foo/?uri=$1 [R,L]
或这个
RewriteRule ^(.*)$ /foo/?uri=%{REQUEST_URI} [R,L]
并使用 Firebug 的网络面板,我发现了更多证据,表明 [L] 标志显然没有按前面提到的 RewriteRule ^$ web/index.html [L] 中的预期工作。规则(从现在起我们称之为规则)。在第一种情况下,我得到 [...]uri=web/index.html , 在第二种情况下 [...]uri=/foo/web/index.html .这意味着 THE RULE 被执行(将 ^$ 重写为 web/index.html),但重写并不止于此。请有更多想法吗?

最佳答案

经过几个小时的搜索和测试,我终于找到了真正的问题和解决方案。希望这也能帮助其他人,当他们遇到同样的问题时。

观察到的行为的原因

每次重定向后都会处理 .htaccess 文件(即使没有 [R] 标志) ,

这意味着在 RewriteRule ^$ web/index.html [L] 之后已处理,mod_rewrite 正确停止重写,转到文件末尾,正确重定向到 /foo/web/index.html , 然后服务器开始处理新位置的 .htaccess 文件,这是同一个文件 .现在只有最后一个重写规则匹配并重定向回 /foo/ (这次使用 [R],因此可以在浏览器中观察到重定向)......并且 .htaccess 文件被一次又一次地处理......

再次为清楚起见:因为只能观察到硬重定向,所以似乎忽略了 [L] 标志,但事实并非如此。相反,.htaccess 被处理两次,在 /foo/ 之间来回重定向。和 /foo/web/index.html .

解决方案

禁止直接访问子文件夹

要将子目录虚拟移动到应用程序根目录,必须使用额外的复杂条件重写。变量 THE_REQUEST对于区分硬重定向和软重定向很有用:

RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]

要匹配此重写规则,必须应用两个条件。首先,在第二行,“本地 URI”必须以 web/ 开头。 (对应于绝对 Web URI /foo/web/)。其次,在第一行,真正的请求 URI 必须以 /foo/web/ 开头。也。这意味着,该规则仅在 web/ 中的文件匹配时才匹配。直接从浏览器请求子文件夹,在这种情况下,我们要进行硬重定向。

重定向到允许的内容从根目录到子文件夹(软)
RewriteCond $1 !^web/
RewriteCond $1 ^(.+\.(html|css|js|ico|png|bmp|jpg|gif))?$
RewriteRule ^(.*)$ web/$1 [L,NC]

我们想重定向到允许的内容,只有当我们还没有这样做时,这是第一个条件。第二个条件指定允许内容的掩码。任何与此掩码匹配的内容都将被软重定向,如果内容不存在,则可能返回 404 错误。

隐藏所有不在子文件夹中或不允许的内容
RewriteRule !^web/ /foo/ [L,R]

这将对所有不以 web/ 开头的 URI 进行硬重定向到应用程序根目录。 (请记住,此时只有以 web/ 开头的请求才是允许内容的内部重定向。

真实例子

在使用上述解决方案提示后,我的“问题”中显示的代码逐渐转变为以下内容:
# disallow directory indexing
Options -Indexes

# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on

# allow access to robots file
RewriteRule ^robots.txt$ - [NC,L]

# mangle core request handler address
# disallow direct access to core request handler
RewriteCond %{THE_REQUEST} !^(GET|POST)\ /asm/core/handleCoreRequest.php
RewriteRule ^core/handleCoreRequest.php$ - [L]
# allow access to request handler under alias
RewriteRule ^core/$ core/handleCoreRequest.php [NC,QSA,L]

# mangle GUI files adressing (move to application root folder)
# disallow direct access to GUI subfolder
RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]
# allow access only to correct filetypes in appropriate locations
RewriteCond $1 ^$ [OR]
RewriteCond $1 ^(images/.+\.(ico|png|bmp|jpg|gif))$ [OR]
RewriteCond $1 ^(css/.+\.css)$ [OR]
RewriteCond $1 ^(js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/css/.+\.css)$ [OR]
RewriteCond $1 ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$
RewriteRule ^(.*)$ web/$1 [L,NC]

# hide all files not in GUI subfolder that are not whitelisted above
RewriteRule !^web/ /foo/ [L,R]

我不喜欢这种方法的一点是,应用程序根文件夹必须硬编码在 .htaccess 文件中(据我所知),因此该文件必须在应用程序安装时生成,而不是简单地复制。

关于.htaccess - 如何让 RewriteRule (.htaccess) 的 [L] 标志真正起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3640194/

相关文章:

apache - 重定向不适用于 htaccess 中的 mod_rewrite

apache - 强制删除 .htaccess 中的 .php 扩展名

.htaccess 单变量 url 重写

apache - 如何解决 Apache 未应用我的重写规则的问题?

.htaccess - htaccess 重写规则 - 允许在 URL 中使用大写字母

php - 如何使用 mod rewrite/htaccess 创建带有两个或多个参数的友好 URL?

javascript - .htaccess 隐藏 .php 文件扩展名,改为显示/(斜杠)

php - 我需要做什么才能打开带有特殊字符的 URL

apache - htaccess 通过查询字符串阻止请求

linux - 503 htaccess 文件仅部分工作