说明 | 为重写引擎定义重写规则 |
---|
语法 | RewriteRule Pattern Substitution [flags] |
---|
作用域 | server config, virtual host, directory, .htaccess |
---|
覆盖项 | FileInfo |
---|
状态 | 扩展(E) |
---|
模块 | mod_rewrite |
---|
兼容性 | cookie-flag在Apache 2.0.40及以后的版本中可用 |
---|
RewriteRule
指令是重写引擎的根本。此指令可以多次使用。每个指令定义一个简单的重写规则。这些规则的定义顺序尤为重要——在运行时,规则是按这个顺序逐一生效的。
Pattern是一个作用于当前URL的perl兼容的正则表达式。"当前URL"是指该规则生效时刻的URL的值。它可能与被请求的URL截然不同,因为其他规则可能在此之前已经发生匹配并对它做了改动。
正则表达式的一些用法示例:
文本
. 任意一个单字符
[chars] 字符类: "chars"中的任意一个字符
[^chars] 字符类: 不在"chars"中的字符
text1|text2 选择: text1 或 text2
量词
? 前面的字符出现 0 或 1 次
* 前面的字符出现 0 或 N 次(N > 0)
+ 前面的字符出现 1 或 N 次(N > 1)
分组
(text) text 组
(常用于设置一个选择的边界,或用于生成后引用:
在RewriteRule中可以用 $
N 引用第N个分组)
锚
^ 锚定到行首
$ 锚定到行尾
转义
\c 对给定的字符c进行转义
(比如对".[]()
"进行转义,等等)
更多有关正则表达式的资料请参见perl正则表达式手册页("perldoc perlre")。另外,在mod_rewrite中,还可以使用否字符('!
')前缀实现反转。比如:"如果当前URL不与模式相匹配"它用于使用否定式匹配模式较容易描述的某些情况,或者作为最后一条规则。
使用否字符以反转匹配模式时,匹配模式中不能使用分组的通配成分
。由于模式不匹配而使分组的内容是空的,所以它是不可能实现的。 因此,如果使用了否定式匹配模式,那么后继的字符串中就不能使用
$N
重写规则中的Substitution是当原始URL与Pattern相匹配时,用来替代(或替换)的字符串。除了纯文本,还可以包含:
- 对Pattern的反向引用(
$N
) - 对最后匹配的RewriteCond的反向引用(
%N
) - 规则条件测试字符串(
%{VARNAME}
)中的服务器变量 - 映射函数调用(
${mapname:key|default}
)
反向引用的$
N(N=0..9)是指用Pattern匹配的第N组的内容去替换URL。服务器变量与RewriteCond
指令的TestString相同。映射函数由RewriteMap
指令决定,其说明也参见该指令。这三种类型变量按上面列表中的顺序被展开。
如上所述,所有的重写规则都是按配置文件中的定义顺序作用于Substitution的。URL被Substitution完全替换,并继续处理直到所有规则处理完毕,除非用L
标记显式地终结(见下文)。
'-
'是一个特殊的替换串,意思是不替换。它可以用于仅仅匹配某些URL而无须替换的情况,比如,在发生替换前,允许以C(chain)标记连接的多个匹配模式同时起作用。
此外,在Substitution之后还可以追加[
flags]
标记作为RewriteRule
指令的第三个参数。
Flags
Flags是一个包含以逗号分隔的下列标记的列表:
目录级重写
为了在.htaccess文件中针对特定目录使用重写引擎,你必须同时设置"RewriteEngine On
"和"Options FollowSymLinks
"。如果管理员禁止了该目录的FollowSymLinks
特性,重写引擎将不会工作,这样做的原因是处于安全方面的考虑。
在服务器级配置中,模式匹配是作用于整个URL的。但是在目录级配置文件.htaccess
中使用重写引擎的时候,目录前缀(一般总是和特定的目录名称相同)将会在模式匹配前被自动移除并在替换完成后被自动添加回去。这个特性对于重写来说是非常重要的,否则你就被迫必须总是对父目录进行匹配,而这并不总是可行的。这里有一个例外:如果替换字符串以"http://
"开头,则不会添加目录前缀,而是强制执行一个外部重定向或代理操作(如果使用了P标志的话)。参见RewriteBase
指令以获得更多信息。
还可以在<Directory>
配置段中使用重写引擎,前缀匹配规则与在.htaccess
中使用重写引擎时完全相同,并且这种做法更加简单。然而,为了避免前缀替换复杂化,我们还是建议尽量将重写规则放置在主服务器或虚拟主机配置部分,而不是放置在<Directory>
配置段中。
虽然重写规则在语法上允许放置在<Location>
配置段中,但这不是必须的,并且我们也反对这样做。
注意:绝对URL 的替换
当替换字段以"http://thishost[:thisport]
"作为前缀时,mod_rewrite
会将它自动剥离出去。在配合生成主机名部分的映射函数使用的时候,这个对隐含的外部重定向URL的简化操作是有用的而且是重要的。下面的第一个例子有助于理解这点。
谨记:由于此功能的存在,以"http://thishost
"为前缀的无条件外部重定向到自身所在的服务器是无效的。要实现一个到自身的重定向,必须使用R标记。
注意:查询字符串
Pattern不会按照查询字符串进行匹配。为了达到这个目的,你必须使用一个带有%{QUERY_STRING}
变量的RewriteCond
指令。当然,你也可以在替换字符串中创建包含查询字符串的URL:在替换字符串串中使用问号,以标明其后的部分应该被重新注入到QUERY_STRING中。而要删除一个已有的请求串,则可以用问号来终结替换字符串。为了联合新旧查询字符串,请使用[QSA]
标志。
以下是所有可能的替换组合及其含义:
在服务器级配置中(httpd.conf
)
对给定的请求"GET /somepath/pathinfo
":
给定的规则 得到的替换字符串
---------------------------------------------- ----------------------------------
^/somepath(.*) otherpath$1 非法,不被支持
^/somepath(.*) otherpath$1 [R] 非法,不被支持
^/somepath(.*) otherpath$1 [P] 非法,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) /otherpath$1 /otherpath/pathinfo
^/somepath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo
通过外部重定向
^/somepath(.*) /otherpath$1 [P] 毫无意义,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^/somepath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo
通过外部重定向
^/somepath(.*) http://thishost/otherpath$1 [P] 毫无意义,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
通过外部重定向
^/somepath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
通过外部重定向
([R]标记是多余的)
^/somepath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
通过内部代理
在/somepath
的目录级配置中
(也就是/physical/path/to/somepath/.htacccess
文件中含有:RewriteBase /somepath
)
对给定的请求"GET /somepath/localpath/pathinfo
":
给定的规则 得到的替换字符串
---------------------------------------------- ----------------------------------
^localpath(.*) otherpath$1 /somepath/otherpath/pathinfo
^localpath(.*) otherpath$1 [R] http://thishost/somepath/otherpath/pathinfo
通过外部重定向
^localpath(.*) otherpath$1 [P] 毫无意义,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) /otherpath$1 /otherpath/pathinfo
^localpath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo
通过外部重定向
^localpath(.*) /otherpath$1 [P] 毫无意义,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^localpath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo
通过外部重定向
^localpath(.*) http://thishost/otherpath$1 [P] 毫无意义,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
通过外部重定向
^localpath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
通过外部重定向
([R]标记是多余的)
^localpath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
通过内部代理
Apache Rewrite解决问号匹配问题
公司网站改版需要把收录的页面301到新地址上,在写Apache Rewrite一个地址的时候怎么都搞不定。代码:
/index.php/index/supply.html?cid=101000
=》
/sell/list-101000.html
后来意识到可能是问号导致的问题,查一下资料发现确实是有问号导致的,修改后解决,代码如下:
RewriteCond %{QUERY_STRING} ^cid=(.+)$
RewriteRule ^/index.php/index/supply\.html$ /sell/list-%1.html? [R=301,L]
说明:
RewriteRule Pattern 在匹配时候不会对问号后面的查询字符进行处理,需要用一个%{QUERY_STRING}变量的RewriteCond指令。
需要主意的问题
1、在新地址/sell/list-%1.html中需要使用%加序号来取得RewriteCond配置中的对应参数内容,而不是通常$(匹配RewriteRule中的内容)
2、新地址/sell/list-%1.html?中需要在尾部加上一个问号来终结查询字符串,否则会出现/sell/list-1000.html?cid=1000的情况。
官方解释
Pattern不会按照查询字符串进行匹配。为了达到这个目的,你必须使用一个带有%{QUERY_STRING}变量的RewriteCond指令。当然,你也可以在替换字符串中创建包含查询字符串的URL:在替换字符串串中使用问号,以标明其后的部分应该被重新注入到QUERY_STRING中。而要删除一个已有的请求串,则可以用问号来终结替换字符串。为了联合新旧查询字符串,请使用[QSA]标志。
网上其他例子(未经测试,貌似是有问题滴)
把 /abc?id=123 => /def.php?id=123 的写法:
RewriteEngine on
RewriteCond %{QUERY_STRING} ^id=(.+)$
RewriteRule ^/abc$ /def.php?sid=%1 [L]