如何强制mod_rewrite跳过实际文件

时间:2012-03-18 04:32:54

标签: regex apache .htaccess mod-rewrite

我有一个应用程序通过index.php路由所有请求。

这是我的设置:

  1. 我在http://www.example.com/sample/
  2. 访问该应用程序
  3. 在文件系统上,应用程序位于/home/chris/www/sample/
  4. 该应用程序的Web可访问目录位于/home/chris/www/sample/app/web
  5. DocumentRoot设置为/home/chris/www
  6. /home/chris/www/sample/.htaccess配置如下:

    RewriteEngine on
    
    RewriteCond   %{REQUEST_URI}    ^/sample/(.+)$
    RewriteCond   %{DOCUMENT_ROOT}/sample/app/web/%1  -f
    RewriteRule   ^/sample/(.*)$    %{DOCUMENT_ROOT}/sample/app/web/%1 [L]
    
    RewriteRule   ^(.+)$            index.php?ws_page=$1 [L,NC,QSA]
    

    我尝试了多种配置,但还没弄清楚为什么我会在调用“真实”文件时继续使用404。

    样本404:

    `http://www.example.com/sample/_css/960/reset.css`
    

    (我希望将其重写为/home/chris/www/sample/app/web/_css/960/reset.css

    修改

    我已经尝试了

    RewriteCond %{REQUEST_URI} !-f
    RewriteCond %{REQUEST_URI} !-d
    RewriteCond %{REQUEST_URI} !-l
    

    并且它们不起作用,因为%{REQUEST_URI}前缀与这些文件的文件系统前缀不匹配。

    编辑2

    为了澄清,我想要表格

    的请求
    `http://www.example.com/sample/foo/bar`
    

    要重写到文件系统对象/home/chris/www/sample/app/web/foo/bar,但仅重写,如果该文件系统对象存在。

4 个答案:

答案 0 :(得分:1)

让您的代码如下:

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /sample

RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+sample/(.+)\s [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond /home/chris/www/sample/app/web/%1 -f [NC]
RewriteRule ^ /sample/app/web/%1 [L]

# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-f
# If the request is not for a valid symlink
RewriteCond %{REQUEST_FILENAME} !-l
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]

答案 1 :(得分:1)

在系统行为差异中阅读mod_rewrite文档时最大的熊市之一(主要和vhost配置了apache在启动时读取的内容以及每个目录上下文中的指令进程。) RewriteRule documentation每个目录重写子部分,以获取更多详细信息。

  

.htaccess文件中使用重写引擎时,每个目录前缀(对于特定目录始终相同)会自动删除以进行RewriteRule模式匹配并在之后自动添加任何相对(不是以斜杠或协议名称开头)替换都会遇到规则集的结尾。有关将哪些前缀添加回相关变量的更多信息,请参阅RewriteBase指令。

以后

  

删除的前缀始终以斜杠结尾,这意味着匹配对于从不具有前导斜杠的字符串。因此,具有^/的模式在每个目录上下文中永远不会匹配。你所做的就是围绕这个做代码。

顺便说一句,这就是为什么指定RewriteBase总是更安全的原因,因为没有这个引擎就会出错。

顺便说一句,这第二个引用可能是错误的,因为前缀添加发生在规则集执行的当时,如果你有一个成功的规则,它是一个不同的相对分支(即目标以{开头) {1}})但是如果没有设置/标记,则引擎会进入具有前导[L]集的任何后续规则。最令人困惑的是,所以我的一般建议是永远不要依赖于落后规则。始终强制立即对每个目录上下文中的成功替换进行内部或外部重定向,因为引擎具有此功能以及此渐入式处理中的其他一些错误。

答案 2 :(得分:0)

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

这两条规则将跳过实际存在的文件(-f)和目录(-d)。

答案 3 :(得分:0)

疯狂的奖励指向任何人可以向我解释为什么我的EOS锚($)应该归咎于RewriteRule无效。

我结束了这个:

RewriteEngine on

RewriteCond   %{REQUEST_URI}    ^/sample/(.+)
RewriteCond   %{DOCUMENT_ROOT}/sample/app/web/%1  -f
RewriteRule   ^(.*)$            app/web/$1 [L,NC,QSA]

RewriteCond   %{REQUEST_URI}    !(^/sample/app/web)
RewriteRule   ^(.+)$            index.php?ws_page=$1 [L,NC,QSA]

非常感谢所有帮助我诊断这种奇怪的人。