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

hon*_*n2a 5 .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]
Run Code Online (Sandbox Code Playgroud)

我的Web应用程序(及其.htaccess文件)位于(从浏览器访问)的foo子文件夹中.它有PHP核心部分和JavaScript GUI部分.从上面的代码可以看出,我想只允许访问单核心脚本,该脚本处理来自GUI和"安全"Web文件的所有请求,并将所有其他请求重定向到基本应用程序地址(最后一个注释指令).DOCUMENT_ROOThttp://localhost/foo/foo/corefoo/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]
Run Code Online (Sandbox Code Playgroud)

这实际上根本不起作用.即使我删除了最后一行,它仍然没有正确地重定向.如果第二个例子中的重定向不起作用,那么第一个例子中的重定向是如何工作的?

如果有人知道任何实际调试这些指令的方法,那对我来说也是非常有益的.我花了几个小时就没有丝毫的线索,这可能是错的.


补充意见


在尝试了bbadour给出的建议之后(不是我之前没有尝试过,但现在我有了第二个意见,我又给了它一个镜头)并且它没有用,我想出了以下观察结果.通过重写最后一行:

RewriteRule ^(.*)$ /foo/?uri=$1 [R,L]
Run Code Online (Sandbox Code Playgroud)

或这个

RewriteRule ^(.*)$ /foo/?uri=%{REQUEST_URI} [R,L]
Run Code Online (Sandbox Code Playgroud)

并且使用Firebug的Net面板,我发现了更多的证据,[L]标志显然没有按照前面提到的RewriteRule ^$ web/index.html [L]规则中的预期工作(从现在开始称之为THE RULE).在第一种情况下,我得到[...]uri=web/index.html,在第二种情况下[...]uri=/foo/web/index.html.这意味着THE RULE被执行(重写^ $到web/index.html),但重写并不止于此.还有什么想法吗?

hon*_*n2a 12

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

观察到的行为的原因


每次重定向后都会处理.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]
Run Code Online (Sandbox Code Playgroud)

要匹配此重写规则,必须应用两个条件.首先,在第二行,"本地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]
Run Code Online (Sandbox Code Playgroud)

我们希望仅在我们尚未完成时才重定向到允许的内容,因此是第一个条件.第二个条件指定允许内容的掩码.与此掩码匹配的任何内容都将被轻柔地重定向,如果内容不存在,则可能返回404错误.

隐藏不在子文件夹中或不允许的所有内容

RewriteRule !^web/ /foo/ [L,R]
Run Code Online (Sandbox Code Playgroud)

这将对应用程序根目录进行硬重定向,以便所有不以此为开头的URI web/(并且请记住,此时只能开始的请求是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]
Run Code Online (Sandbox Code Playgroud)


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