代码之家  ›  专栏  ›  技术社区  ›  hon2a

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

  •  5
  • hon2a  · 技术社区  · 14 年前

    对新来者:在试图全面描述我的问题和表达我的问题时,我产生了大量的文本。如果你不想看整件事, 我的观察(读“证据”) [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/ foo/core JavaScript GUI部分位于 foo/web . 从上面的代码可以看出,我只想允许访问处理来自GUI的所有请求的单核心脚本和“安全”web文件,并将所有其他请求重定向到基本应用程序地址(最后一个注释的指令)。


    问题


    行为

    它一直工作,直到我通过取消最后一个重定向指令的注释来尝试最后一部分。 如果我多注释几行,相应的页面部分就会停止工作,等等。

    http://localhost/foo/ 一次又一次,永远。

    我不明白的是这个规则的处理过程:

    RewriteRule ^$ web/index.html [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的netpanel,我发现了更多的证据,表明[L]标志显然没有像前面提到的那样工作 规则(从现在起我们称之为规则)。在第一种情况下,我得到 [...]uri=web/index.html [...]uri=/foo/web/index.html . 这意味着规则将被执行(将^$重写到web)/索引.html),但重写并没有就此停止。还有什么想法吗?

    3 回复  |  直到 5 年前
        1
  •  12
  •   hon2a    14 年前

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

    观察行为的原因


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

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

    再次澄清一下:因为只能观察到硬重定向,所以似乎忽略了[L]标志,但事实并非如此。相反,处理.htaccess两次,在 .



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

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

    要匹配此重写规则,必须应用两个条件。首先,在第二行,“localuri”必须以 web/ (与绝对web URI相对应) /foo/web/ ). 第二,在第一行,真正的请求URI必须以 /foo/网络/ 我也是。这意味着,只有在 网络/ 子文件夹是直接从浏览器请求的,在这种情况下,我们要做一个硬重定向。

    重定向到允许的内容从根目录到子文件夹(软)

    RewriteCond $1 !^web/
    RewriteCond $1 ^(.+\.(html|css|js|ico|png|bmp|jpg|gif))?$
    RewriteRule ^(.*)$ web/$1 [L,NC]
    

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

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

    RewriteRule !^web/ /foo/ [L,R]
    

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



    我在“问题”中所显示的代码在使用上述解决方案提示后逐渐转变为:

    # 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]
    


        2
  •  0
  •   aularon    14 年前

    为了调试,试着简化你的正则表达式和你要求的url(你想要匹配的完整url的一部分),看看它是否工作,现在一步一步地,向正则表达式和测试url添加更多的位,直到你找到停止工作的地方。

        3
  •  0
  •   bbadour    14 年前

    RewriteRule ^(.*)$ /foo/ [R,L]
    

    如果它仍然循环,放一个 RewriteCond /foo/