RewriteCond REQUEST_URI - ^ 没有按预期工作

Posted

技术标签:

【中文标题】RewriteCond REQUEST_URI - ^ 没有按预期工作【英文标题】:RewriteCond REQUEST_URI - ^ doesn't work as expected 【发布时间】:2012-09-10 01:23:22 【问题描述】:

我正在使用 codeigniter 构建一个站点。我在 .htaccess 文件中有一系列重写条件和规则。第一组规则根据 uri 的第一段打开或关闭 SSL。

然后它再次循环,如果找到匹配项,则适当地重定向页面。如果不匹配,并且 uri 不以列出的任何字符串开头,它会将您重定向到另一个页面。如果不满足条件,则进入索引页面。

问题在于我的第一组打开和关闭 SSL 的规则。我想指定 uri 必须以管理员或安全方式开始。但是如果我将 ^ 添加到字符串的开头,一切都会中断。这是我所拥有的:

RewriteCond %HTTPS off
RewriteCond %REQUEST_URI ^/?(admin|secure)
RewriteRule ^(.*)$ https://%HTTP_HOST/$1 [R=301,L]

RewriteCond %HTTPS on 
RewriteCond %REQUEST_URI !^/?(admin|secure)
RewriteRule ^(.*)$ http://%HTTP_HOST/$1 [R=301,L]

...specific rewrites here
RewriteRule ^secure-form1$ secure/contract/secure-form1 [L]
RewriteRule ^secure$ secure/article/secure [L]

RewriteCond %HTTP_HOST ^www.example.com$ 
RewriteCond %REQUEST_URI !^/(admin|form|secure|page)/
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-d
RewriteRule ^(.*)$ index.php/page/article/$1 [L]

RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-d
RewriteRule ^(.*)$ index.php/$1 [L]

如果我在前 2 个重写条件(https 开启和关闭)中保留 ^ 符号,那么 http://www.example.com/secure 重写为 https://www.example.com/index.php/secure/article/secure 这是最后的重写规则。 url 实际上在浏览器中变成了这个。

如果我从前 2 个重写条件中取出 ^ 符号,那么它会转到正确的页面。但我确实需要指定 uri 的开头,因为在 uri 中间(并在斜线后面)有其他页面不应该使用 SSL。

这个我想不通。

【问题讨论】:

你确定你的 php 代码中没有重定向吗? 【参考方案1】:

试试这个:

RewriteCond %HTTPS off 
RewriteCond %HTTP_HOST ^(.*)$ 
RewriteRule ^/?(admin|secure)$ https://%1/$1 [R=301,L]

【讨论】:

是的!太感谢了!我没想过要那样做。它现在按预期工作。【参考方案2】:

老问题,我知道,但如果您真的想坚持 %REQUEST_URI 条件,还有另一种解决方案可能会更好:

RewriteCond %HTTPS !=on
RewriteCond %REQUEST_URI ^/?(admin|secure)$
RewriteRule ^ https://%HTTP_HOST%REQUEST_URI [R=301,L]

与 OP 的主要区别在于包含 /? 以检查 URI 开头是否存在正斜杠。 AFAIK,不同的 Apache 安装可能包括也可能不包括 %REQUEST_URI 中的斜线。

这样做的一个好处是您可以将规则应用于多个条件:

RewriteCond %HTTPS !=on
RewriteCond %REQUEST_URI ^/?admin$ [OR]
RewriteCond %REQUEST_URI ^/?secure$ [OR]
RewriteCond %REQUEST_URI ^/?top-secret$
RewriteRule ^ https://%HTTP_HOST%REQUEST_URI [R=301,L]

就我认为的方式而言,这比使用一长串以管道分隔的字符串更容易处理。与单个正则表达式相比,这是以潜在的效率损失为代价的,但您可以进行一些其他改进来抵消这一点:

使用 lexographically equal 运算符!=on。如果您只使用off,它将被视为正则表达式。

消除 RewriteRule 模式,将其替换为单个插入符号,然后使用环境变量 %HTTP_HOST%REQUEST_URI。这节省了较长的正则表达式模式以及反向引用的开销。

【讨论】:

正如您所写,“不同的 Apache 安装可能会或可能不会在 %REQUEST_URI 中包含开始斜杠”。所以如果不是,那么你的代码是错误的,因为%HTTP_HOST%REQUEST_URI 不会包含任何斜线分隔符。 很好的答案。不过有一个小问题。您提到 REQUEST_URI 可能包含也可能不包含开头的正斜杠。因此,在重建 URL 时依赖包含它似乎是不寻常的。将斜杠显式添加到重定向 URL 似乎更好,并可能在 RewriteRule 或其他不依赖 REQUEST_URI 的解决方案(包括斜杠)中捕获路径,因此您的整个解决方案涵盖了这两种设置。目前,如果 REQUEST_URI 中没有斜杠,重定向 URL 将被破坏,将主机与 URI 和没有斜杠合并。谢谢。 这些是@Ωmega 和@NigelPeck 关于丢失斜线的好点。我想我在想,一旦您确定了环境的需求,就可以添加斜线。如果您绝对需要支持这两种情况,一个简单的解决方法是在重写路径中简单地包含斜杠,因为www.example.com//top-secret 是一个有效的 URI。

以上是关于RewriteCond REQUEST_URI - ^ 没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

当 REQUEST_URI 与 htaccess apache2 不匹配时 RewriteCond

RewriteCond %{REQUEST_URI}

RewriteCond %{REQUEST_URI}

RewriteCond REQUEST_URI - ^ 没有按预期工作

对于SSL,将http:转发到https:

Nginx伪静态处理,高手进来,帮我处理下。