mod_rewrite
最近似乎有相当数量的线程浮出水面,对它的某些方面如何工作有点混淆.结果我编写了一些关于常见功能的注释,也许还有一些烦人的细微差别.
您遇到过哪些其他功能/常见问题mod_rewrite
?
mod_rewrite
规则可以放在httpd.conf
文件中,也可以放在.htaccess
文件中.如果您有权访问httpd.conf
,则在此处放置规则将提供性能优势(因为规则处理一次,而不是每次.htaccess
调用文件时).
可以从httpd.conf
文件中启用日志记录(包括
):
# logs can't be enabled from .htaccess # loglevel > 2 is really spammy! RewriteLog /path/to/rewrite.log RewriteLogLevel 2
将所有请求汇集到一个点:
RewriteEngine on # ignore existing files RewriteCond %{REQUEST_FILENAME} !-f # ignore existing directories RewriteCond %{REQUEST_FILENAME} !-d # map requests to index.php and append as a query string RewriteRule ^(.*)$ index.php?query=$1
自Apache 2.2.16起,您也可以使用FallbackResource
.
处理301/302重定向:
RewriteEngine on # 302 Temporary Redirect (302 is the default, but can be specified for clarity) RewriteRule ^oldpage\.html$ /newpage.html [R=302] # 301 Permanent Redirect RewriteRule ^oldpage2\.html$ /newpage.html [R=301]
注意:外部重定向是隐含的302重定向:
# this rule: RewriteRule ^somepage\.html$ http://google.com # is equivalent to: RewriteRule ^somepage\.html$ http://google.com [R] # and: RewriteRule ^somepage\.html$ http://google.com [R=302]
强制SSL
RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://example.com/$1 [R,L]
常用标志:
[R]
或[redirect]
- 强制重定向(默认为302临时重定向)
[R=301]
或[redirect=301]
- 强制执行301永久重定向
[L]
或[last]
- 停止重写过程(见常见陷阱中的注释)
[NC]
或[nocase]
- 指定匹配应不区分大小写
使用长形式的标志通常更具可读性,并且可以帮助其他人以后阅读您的代码.
您可以使用逗号分隔多个标志:
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
混合mod_alias
风格重定向mod_rewrite
# Bad Redirect 302 /somepage.html http://example.com/otherpage.html RewriteEngine on RewriteRule ^(.*)$ index.php?query=$1 # Good (use mod_rewrite for both) RewriteEngine on # 302 redirect and stop processing RewriteRule ^somepage.html$ /otherpage.html [R=302,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # handle other redirects RewriteRule ^(.*)$ index.php?query=$1
注意:您可以混合mod_alias
使用mod_rewrite
,但它涉及的工作不仅仅是处理上面的基本重定向.
上下文影响语法
在.htaccess
文件中,RewriteRule模式中不使用前导斜杠:
# given: GET /directory/file.html # .htaccess # result: /newdirectory/file.html RewriteRule ^directory(.*)$ /newdirectory$1 # .htaccess # result: no match! RewriteRule ^/directory(.*)$ /newdirectory$1 # httpd.conf # result: /newdirectory/file.html RewriteRule ^/directory(.*)$ /newdirectory$1 # Putting a "?" after the slash will allow it to work in both contexts: RewriteRule ^/?directory(.*)$ /newdirectory$1
[L]不是最后一个!(有时)
该[L]
标志停止处理该通过规则集的任何进一步重写规则.但是,如果在该传递中修改了URL并且您在.htaccess
上下文或
部分中,那么您修改的请求将再次通过URL解析引擎传回.在下一次传球中,这次可能会匹配不同的规则.如果您不理解这一点,通常看起来您的[L]
旗帜没有效果.
# processing does not stop here RewriteRule ^dirA$ /dirB [L] # /dirC will be the final result RewriteRule ^dirB$ /dirC
我们的重写日志显示规则运行两次,URL更新两次:
rewrite 'dirA' -> '/dirB' internal redirect with /dirB [INTERNAL REDIRECT] rewrite 'dirB' -> '/dirC'
解决这个问题的最好方法是使用[END]
标志(请参阅Apache文档)而不是[L]
标志,如果您真的想要停止所有进一步处理规则(以及后续传递).但是,该[END]
标志仅适用于Apache v2.3.9 +,因此如果您使用的是v2.2或更低版本,则只会使用该[L]
标志.
对于早期版本,您必须依赖RewriteCond
语句来防止在URL解析引擎的后续传递中匹配规则.
# Only process the following RewriteRule if on the first pass RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ...
或者您必须确保您的RewriteRule位于上下文(即httpd.conf
)中,不会导致您的请求被重新解析.
如果您需要"阻止"内部重定向/重写发生在.htaccess中,请查看
RewriteCond %{ENV:REDIRECT_STATUS} ^$
条件,如这里所讨论的.
与RewriteBase的交易:
您几乎总是需要设置RewriteBase.如果不这样做,apache会猜测您的base是目录的物理磁盘路径.所以从这开始:
RewriteBase /
其他陷阱:
1-有时禁用MultiViews是个好主意
Options -MultiViews
我对所有MultiViews功能都不太熟悉,但我知道它在活动时会弄乱我的mod_rewrite规则,因为它的一个属性是尝试"猜测"它认为我正在寻找的文件的扩展名.
我将解释:假设你的web目录,file1.php和file2.php中有2个php文件,你将这些条件和规则添加到.htaccess:
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ file1.php/$1
您假设所有与文件或目录不匹配的URL都将被file1.php抓取.惊喜!对于URL http:// myhost/file2/somepath,此规则不受尊重.相反,你被带到file2.php.
发生了什么事情,MultiViews自动猜到你真正想要的网址是http://myhost/file2.php/somepath,很高兴带你到那儿.
现在,你不知道刚刚发生了什么,你就是在那一点上质疑你认为你对mod_rewrite有所了解的一切.然后,您开始使用规则来尝试理解这种新情况背后的逻辑,但是您测试的越多,它所产生的感觉越少.
好的,简而言之,如果您希望mod_rewrite以接近逻辑的方式工作,关闭MultiViews是朝着正确方向迈出的一步.
2-启用FollowSymlinks
Options +FollowSymLinks
那一个,我真的不知道细节,但我已经看过很多次了,所以就去做吧.
方程可以通过以下示例完成:
RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC] # %1 is the string that was found above # %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;" #RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*) # <> is used as an string separator/indicator, can be replaced by any other character RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC] RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]
动态负载平衡:
如果使用mod_proxy来平衡系统,则可以添加动态范围的工作服务器.
RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC] RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]