On this page
Apache 模块 mod_rewrite
Description: | 提供基于规则的重写引擎以即时重写请求的 URL |
---|---|
Status: | Extension |
Module Identifier: | rewrite_module |
Source File: | mod_rewrite.c |
Summary
mod_rewrite模块使用基于规则的重写引擎(基于 PCRE 正则表达式解析器)来实时重写请求的 URL。默认情况下,mod_rewrite将 URL Map 到文件系统路径。但是,它也可以用于将一个 URL 重定向到另一个 URL,或调用内部代理获取。
mod_rewrite提供了一种灵活而强大的方法,可以使用无限数量的规则来操作 URL。每个规则可以具有无限数量的附加规则条件,以允许您基于服务器变量,环境变量,HTTP Headers 或时间戳重写 URL。
mod_rewrite在完整的 URL 路径(包括 path-info 部分)上运行。可以在httpd.conf
或.htaccess
中调用重写规则。重写规则生成的路径可以包含查询字符串,或者可以导致内部子处理,外部请求重定向或内部代理吞吐量。
详细的 mod_rewrite 文档中提供了更多详细信息,讨论和示例。
Logging
mod_rewrite在trace1
到trace8
日志级别提供其操作的详细日志记录。可以使用LogLevel指令专门为mod_rewrite设置日志级别:直到级别debug
,都不会记录任何操作,而trace8
表示实际上已记录了所有操作。
Note
对mod_rewrite使用较高的跟踪日志级别将大大降低 Apache HTTP Server 的速度!使用高于trace2
的日志级别仅用于调试!
Example
LogLevel alert rewrite:trace3
RewriteLog
那些熟悉mod_rewrite早期版本的人无疑会在寻找RewriteLog
和RewriteLogLevel
指令。上面提到的新的每模块日志记录配置已完全取代了此功能。
要仅获取特定于mod_rewrite的日志消息,请通过 grep 通过管道传递日志文件:
tail -f error_log|fgrep '[rewrite:'
RewriteBase Directive
Description: | 设置每个目录重写的基本 URL |
---|---|
Syntax: | RewriteBase URL-path |
Default: | None |
Context: | directory, .htaccess |
Override: | FileInfo |
Status: | Extension |
Module: | mod_rewrite |
RewriteBase
指令指定用于替换相对路径的每个目录(htaccess)RewriteRule指令的 URL 前缀。
在每个目录(htaccess)上下文中的替换中使用相对路径时,此指令是“必需的”,除非满足以下任一条件:
原始请求及其替换位于DocumentRoot下方(与其他方式(例如Alias)无法访问)。
包含RewriteRule的目录的* filesystem *路径(相对替换后缀)也作为服务器上的 URL 路径有效(这种情况很少见)。
在 Apache HTTP Server 2.4.16 和更高版本中,当通过Alias或mod_userdirMap 请求时,可以忽略此伪指令。
在下面的示例中,由于资源与文档根目录无关,因此RewriteBase
是避免重写为 http://example.com/opt/myapp-1.2.3/welcome.html 所必需的。这种配置错误通常会导致服务器在文档根目录下查找“ opt”目录。
DocumentRoot "/var/www/example.com"
AliasMatch "^/myapp" "/opt/myapp-1.2.3"
<Directory "/opt/myapp-1.2.3">
RewriteEngine On
RewriteBase "/myapp/"
RewriteRule "^index\.html$" "welcome.html"
</Directory>
RewriteCond Directive
Description: | 定义重写的条件 |
---|---|
Syntax: | RewriteCond TestString CondPattern [flags] |
Context: | 服务器配置,虚拟主机,目录,.htaccess |
Override: | FileInfo |
Status: | Extension |
Module: | mod_rewrite |
RewriteCond
指令定义规则条件。一个或多个RewriteCond
可以位于RewriteRule指令之前。然后,仅当 URI 的当前状态都匹配其模式时才使用以下规则,如果满足这些条件,则 和 。
- TestString *是一个字符串,除了纯文本之外,还可以包含以下扩展结构:
RewriteRule 反向引用 :这些是形式为
$N
(0 <= N <= 9)的反向引用。 $ 1 到$ 9 允许从RewriteRule
访问模式的分组部分(在括号中),这受当前RewriteCond
条件的限制。 $ 0 提供对该模式匹配的整个字符串的访问。RewriteCond 反向引用 :这些是形式为
%N
1 **(0 <= N <= 9)的反向引用。从%1 到%9,可以从当前条件集中最后匹配的RewriteCond
访问模式的分组部分(再次用括号括起来)。 %0 提供对与该模式匹配的整个字符串的访问。RewriteMap 扩展 :这些是形式
${mapname:key|default}
的扩展。有关更多详细信息,请参见RewriteMap 的文档。Server-Variables :这些变量的形式为
%{
* NAME_OF_VARIABLE *}
其中* NAME_OF_VARIABLE *可以是以下列表中的字符串:
HTTP headers: | 连接和请求: | |
---|---|---|
HTTP_ACCEPT HTTP_COOKIE HTTP_FORWARDED HTTP_HOST HTTP_PROXY_CONNECTION HTTP_REFERER HTTP_USER_AGENT |
AUTH_TYPE CONN_REMOTE_ADDR CONTEXT_PREFIX CONTEXT_DOCUMENT_ROOT IPV6 PATH_INFO QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_PORT REMOTE_USER REQUEST_METHOD SCRIPT_FILENAME |
|
server internals: | 日期和时间: | specials: |
DOCUMENT_ROOT SCRIPT_GROUP SCRIPT_USER SERVER_ADDR SERVER_ADMIN SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE |
TIME_YEAR TIME_MON TIME_DAY TIME_HOUR TIME_MIN TIME_SEC TIME_WDAY TIME |
API_VERSION CONN_REMOTE_ADDR HTTPS IS_SUBREQ REMOTE_ADDR REQUEST_FILENAME REQUEST_SCHEME REQUEST_URI THE_REQUEST |
这些变量都对应于类似命名的 HTTP MIME Headers,Apache HTTP Server 的 C 变量或 Unix 系统的struct tm
字段。多数记录在here或《手册》或 CGI 规范的其他地方。
SERVER_NAME 和 SERVER_PORT 分别取决于UseCanonicalName和UseCanonicalPhysicalPort的值。
mod_rewrite特殊的内容包括以下内容。
API_VERSION
- 这是当前 httpd 构建中 Apache httpd 模块 API(服务器和模块之间的内部接口)的版本,如 include/ap_mmn.h 中所定义。模块 API 版本与使用中的 Apache httpd 版本相对应(例如,在 Apache httpd 1.3.14 的发行版中为 19990320:10),但是模块作者主要感兴趣。
CONN_REMOTE_ADDR
- 从 2.4.8 开始:连接的对等 IP 地址(请参见mod_remoteip模块)。
HTTPS
- 如果连接使用的是 SSL/TLS,则将包含文本“ on”,否则将包含“ off”。 (无论是否加载了mod_ssl,都可以安全地使用此变量)。
IS_SUBREQ
- 如果当前正在处理的请求是子请求,则将包含文本“ true”,否则将包含“ false”。子请求可能由需要解析其他文件或 URI 才能完成其任务的模块生成。
REMOTE_ADDR
- 远程主机的 IP 地址(请参阅mod_remoteip模块)。
REQUEST_FILENAME
- 如果在引用
REQUEST_FILENAME
时服务器已经确定了与请求匹配的文件或脚本的本地文件系统的完整路径,则为该路径。否则,例如在虚拟主机上下文中使用时,该值与REQUEST_URI
相同。根据AcceptPathInfo的值,服务器可能只使用了REQUEST_URI
的某些前导组件将请求 Map 到文件。
- 如果在引用
REQUEST_SCHEME
- 将包含请求的方案(通常为“ http”或“ https”)。该值可以受ServerName影响。
REQUEST_URI
- 所请求 URI 的路径部分,例如“ /index.html”。这特别排除了查询字符串,该查询字符串可以作为其自己的名为
QUERY_STRING
的变量使用。
- 所请求 URI 的路径部分,例如“ /index.html”。这特别排除了查询字符串,该查询字符串可以作为其自己的名为
THE_REQUEST
- 浏览器发送到服务器的完整 HTTP 请求行(例如“
GET /index.html HTTP/1.1
”)。这不包括浏览器发送的任何其他 Headers。与以下大多数其他变量不同,此值尚未被转义(解码)。
- 浏览器发送到服务器的完整 HTTP 请求行(例如“
如果* TestString 具有特殊值expr
,则 CondPattern *将被视为ap_expr。如果未提供novary
标志,则表达式中引用的 HTTP Headers 将添加到 Vary Headers 中。
您应该注意的其他事项:
- 变量 SCRIPT_FILENAME 和 REQUEST_FILENAME 包含相同的值-Apache HTTP Server 内部
request_rec
结构的filename
字段的值。第一个名称是众所周知的 CGI 变量名称,第二个名称是 REQUEST_URI 的对应名称(其中包含request_rec
的uri
字段的值)。
如果发生替换并且重写 continue,则两个变量的值将相应更新。
如果用于每个服务器的上下文(,即,在将请求 Map 到文件系统之前),则 SCRIPT_FILENAME 和 REQUEST_FILENAME 不能包含完整的本地文件系统路径,因为在此处理阶段该路径未知。在这种情况下,两个变量最初都将包含 REQUEST_URI 的值。为了在每个服务器上下文中获取请求的完整本地文件系统路径,请使用基于 URL 的前瞻%{LA-U:REQUEST_FILENAME}
来确定 REQUEST_FILENAME 的最终值。
%{ENV:variable}
,其中* variable *可以是任何环境变量,也可以使用。这是通过内部 Apache httpd 结构查找的(如果未在此找到),则通过getenv()
从 Apache httpd 服务器进程中查找。%{SSL:variable}
(其中* variable *是SSL 环境变量的名称),无论是否加载mod_ssl均可使用,但如果未加载,则始终会扩展为空字符串。示例:%{SSL:SSL_CIPHER_USEKEYSIZE}
可能会扩展为128
。即使未设置SSLOptions指令的StdEnvVars
选项,这些变量仍然可用。%{HTTP:header}
(* header *可以是任何 HTTP MIME-header 名称)始终可用于获取 HTTP 请求中发送的 Headers 的值。示例:%{HTTP:Proxy-Connection}
是 HTTP Headers```+202+`''的值。
如果在条件中使用 HTTP Headers,则该条件将被添加到响应的 Vary Headers 中,以防条件对请求的评估为 true。如果条件对于请求的评估结果为 false,则“不”添加。为了适当地缓存,需要将 HTTP Headers 添加到响应的 Vary Headers 中。
必须记住,在“ ornext|OR
”标志的情况下,条件遵循短路逻辑,因此可能根本无法评估某些条件。
- %{LA-U:variable}可用于执行内部(基于 URL)子请求以确定* variable *的最终值的前瞻。这可用于访问变量以进行重写,该变量在当前阶段尚不可用,但将在以后的阶段中进行设置。
例如,要根据每个服务器上下文(httpd.conf
文件)中的REMOTE_USER
变量进行重写,您必须使用%{LA-U:REMOTE_USER}
-此变量是由授权阶段设置的,授权阶段在 URL 转换阶段之后(在mod_rewrite操作期间) 。
另一方面,由于mod_rewrite通过 API 的 Fixup 阶段实现了其按目录的上下文(.htaccess
文件),并且由于授权阶段在此阶段之前*进行,所以您只能在该上下文中使用%{REMOTE_USER}
。
%{LA-F:variable}
可用于执行内部(基于文件名的)子请求,以确定* variable *的最终值。在大多数情况下,这与上面的 LA-U 相同。
CondPattern 是条件模式,是应用于 TestString 的当前实例的正则表达式。首先对 TestString 进行评估,然后再与 CondPattern *进行匹配。
CondPattern 通常是 perl 兼容的正则表达式*,但是还有其他语法可用于对* Teststring *执行其他有用的测试:
无论使用哪种* CondPattern *,都可以在模式字符串前加上'
!
'字符(感叹号)以否定条件结果。您可以执行字典字符串比较:
<CondPattern
- Lexicographically precedes
将* CondPattern 视为纯字符串,并按字典 Sequences 将其与 TestString 进行比较。如果 TestString 在字典上位于 CondPattern *之前,则为 true。
- Lexicographically precedes
>CondPattern
- Lexicographically follows
将* CondPattern 视为纯字符串,并按字典 Sequences 将其与 TestString 进行比较。如果 TestString 在字典上紧随 CondPattern *,则为 true。
- Lexicographically follows
=CondPattern
- Lexicographically equal
将* CondPattern 视为纯字符串,并按字典 Sequences 将其与 TestString 进行比较。如果 TestString 在字典上等于 CondPattern (两个字符串完全相同,一个字符一个字符),则为 true。如果 CondPattern 为""
(两个引号),则将 TestString *与空字符串进行比较。
- Lexicographically equal
<=CondPattern
- 从词法上小于或等于
将* CondPattern 视为纯字符串,并按字典 Sequences 将其与 TestString 进行比较。如果 TestString 在字典上在 CondPattern 之前,或者等于 CondPattern *(两个字符串相同,一个字符一个字符),则为 true。
- 从词法上小于或等于
>=CondPattern
- 从词法上大于或等于
将* CondPattern 视为纯字符串,并按字典 Sequences 将其与 TestString 进行比较。如果 TestString 在字典上紧随 CondPattern 或等于 CondPattern *(两个字符串相同,一个字符一个字符),则为 true。
- 从词法上大于或等于
Note
字符串比较运算符是* CondPattern *参数的一部分,如果使用了引号,则必须将其包括在引号中。例如。
RewriteCond %{HTTP_USER_AGENT} "=This Robot/1.0"
您可以执行整数比较:
-eq
- 在数字上等同于
- TestString 被视为整数,并与 CondPattern *进行数值比较。如果两者在数值上相等,则为 true。
- 在数字上等同于
-ge
- 在数字上 g 大于或 e 等于
- TestString 被视为整数,并与 CondPattern 进行数值比较。如果 TestString 在数值上大于或等于 CondPattern *,则为 true。
- 在数字上 g 大于或 e 等于
-gt
- 在数字上* g 收割者 t **汉
- TestString 被视为整数,并与 CondPattern 进行数值比较。如果 TestString 在数值上大于 CondPattern *,则为 true。
- 在数字上* g 收割者 t **汉
-le
- 在数值上小于或等于
- TestString 被视为整数,并与 CondPattern 进行数值比较。如果 TestString 在数值上小于或等于 CondPattern *,则为 true。通过使用 -L 或 -h 变体,避免与 -l 混淆。
- 在数值上小于或等于
-lt
- 从数字上看* l ess t ** han
- TestString 被视为整数,并与 CondPattern 进行数值比较。如果 TestString 在数值上小于 CondPattern *,则为 true。通过使用 -L 或 -h 变体,避免与 -l 混淆。
- 从数字上看* l ess t ** han
-ne
- 在数值上 n 或 e 等于
- TestString 被视为整数,并与 CondPattern *进行数值比较。如果两者在数值上不同,则为 true。这等效于
!-eq
。
- TestString 被视为整数,并与 CondPattern *进行数值比较。如果两者在数值上不同,则为 true。这等效于
- 在数值上 n 或 e 等于
您可以执行各种文件属性测试:
-d
- 是 d 烦躁。
将* TestString *视为路径名,并测试它是否存在,并且是目录。
- 是 d 烦躁。
-f
- 是常规 f ile。
将* TestString *视为路径名,并测试它是否存在,并且是常规文件。
- 是常规 f ile。
-F
- 是现有文件,通过子请求。
检查* TestString *是否为有效文件,可通过该路径的所有服务器当前配置的访问控件进行访问。这使用内部子请求进行检查,因此请谨慎使用-它可能会影响服务器的性能!
- 是现有文件,通过子请求。
-h
- 是符号链接,bash 约定。
参见 -l 。
- 是符号链接,bash 约定。
-l
- 是象征性的墨水。
将* TestString *视为路径名并测试它是否存在,并且是符号链接。如果有混淆的可能,例如使用 -lt 或 -le 测试时,也可以使用 -L 或 -h 的 bash 约定。
- 是象征性的墨水。
-L
- 是符号链接,bash 约定。
参见 -l 。
- 是符号链接,bash 约定。
-s
- 是常规文件,带有 s 大小。
将* TestString *视为路径名,并测试它是否存在,并且是大小大于零的常规文件。
- 是常规文件,带有 s 大小。
-U
- 是现有的 URL,通过子请求。
检查* TestString *是否为有效的 URL,可通过该路径的所有服务器当前配置的访问控件进行访问。这使用内部子请求进行检查,因此请谨慎使用-它可能会影响服务器的性能!
- 是现有的 URL,通过子请求。
仅此标志返回有关访问控制,身份验证和授权之类的信息。该标志不返回有关已配置处理程序(静态文件,CGI,代理等)将返回的状态代码的信息。
-x
- 具有 e x 可执行权限。
将* TestString *视为路径名,并测试它是否存在,并具有可执行权限。这些权限是根据基础 os 确定的。
- 具有 e x 可执行权限。
For example:
RewriteCond /var/www/%{REQUEST_URI} !-f
RewriteRule ^(.+) /other/archive/$1 [R]
- 如果* TestString 具有特殊值
expr
,则 CondPattern *将被视为ap_expr。
在下面的示例中,-strmatch
用于将REFERER
与站点主机名进行比较,以阻止不需要的热链接。
RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://%{HTTP_HOST}/*'"
RewriteRule "^/images" "-" [F]
您还可以通过将 [
* flags * ]
作为RewriteCond
指令的第三个参数添加,来为* CondPattern 设置特殊标志,其中 flags *是以下任意标志的逗号分隔列表:
'
nocase|NC
'( n o c ase)
这使得测试用例不敏感-在扩展的* TestString 和 CondPattern 中,“ A-Z”和“ a-z”之间的差异都将被忽略。该标志仅对 TestString 和 CondPattern *之间的比较有效。它对文件系统和子请求检查没有影响。'
ornext|OR
'( 或 下一个条件)
使用它可以将规则条件与局部 OR(而不是隐式 AND)组合。典型示例:
RewriteCond "%{REMOTE_HOST}" "^host1" [OR]
RewriteCond "%{REMOTE_HOST}" "^host2" [OR]
RewriteCond "%{REMOTE_HOST}" "^host3"
RewriteRule ...some special stuff for any of these hosts...
没有此标志,您将必须写入条件/规则对三遍。
- '
novary|NV
'( n o v ary)
如果在这种情况下使用 HTTP Headers,则此标志阻止将此 Headers 添加到响应的 Vary Headers 中。
如果此响应的表示形式随此 Headers 的值而变化,则使用此标志可能会中断对响应的正确缓存。因此,仅在了解 Vary Headers 的含义的情况下,才应使用此标志。
Example:
要根据请求的```+239+`''Headers 重写网站的主页,可以使用以下命令:
RewriteCond "%{HTTP_USER_AGENT}" "(iPhone|Blackberry|Android)"
RewriteRule "^/$" "/homepage.mobile.html" [L]
RewriteRule "^/$" "/homepage.std.html" [L]
说明:如果使用将自身标识为移动浏览器的浏览器(请注意,示例不完整,因为还有许多其他移动平台),则将提供主页的移动版本。否则,将提供标准页面。
RewriteEngine Directive
Description: | 启用或禁用运行时重写引擎 |
---|---|
Syntax: | RewriteEngine on|off |
Default: | RewriteEngine off |
Context: | 服务器配置,虚拟主机,目录,.htaccess |
Override: | FileInfo |
Status: | Extension |
Module: | mod_rewrite |
RewriteEngine
指令启用或禁用运行时重写引擎。如果将其设置为off
,则此模块完全不进行运行时处理。它甚至不更新SCRIPT_URx
环境变量。
使用此伪指令可以在特定上下文中禁用规则,而不是 Comments 掉所有的RewriteRule伪指令。
请注意,重写配置不会被虚拟主机继承。这意味着您需要为每个要在其中使用重写规则的虚拟主机使用RewriteEngine on
指令。
如果在未将RewriteEngine
设置为on
的上下文中定义了prg
类型的RewriteMap指令,则不会在服务器初始化期间启动它们
RewriteMap Directive
Description: | 定义用于键查找的 Map 功能 |
---|---|
Syntax: | RewriteMap MapName MapType:MapSource [MapTypeOptions] |
Context: | 服务器配置,虚拟主机 |
Status: | Extension |
Module: | mod_rewrite |
Compatibility: | 第三个参数 MapTypeOptions 仅在 Apache 2.4.29 和更高版本中可用 |
RewriteMap
指令定义了一个* Rewriting Map *,Map 函数可在规则替换字符串中使用它,以通过键查找插入/替换字段。查找的来源可以有多种类型。
MapName是 Map 的名称,将用于通过以下结构之一为重写规则的替换字符串指定 Map 功能:
** ${
* MapName * :
* LookupKey * }
${
* MapName * :
* LookupKey * |
* DefaultValue * }
**
当发生这种构造时,将查询 Map* MapName 并查找键 LookupKey 。如果找到了键,则 Map 函数构造将被 SubstValue 替代。如果未找到键,则用 DefaultValue 替换,如果未指定 DefaultValue *,则用空字符串替换。空值的行为就像缺少键一样,因此无法区分空值键和不存在键。
例如,您可以将RewriteMap
定义为:
RewriteMap examplemap "txt:/path/to/file/map.txt"
然后,您将可以在RewriteRule中使用此 Map,如下所示:
RewriteRule "^/ex/(.*)" "${examplemap:$1}"
- MapTypeOptions 参数的含义取决于特定的 MapType *。有关更多信息,请参见Using RewriteMap。
可以使用* MapType 和 MapSource *的以下组合:
txt
- 一个纯文本文件,包含用空格分隔的键/值对,每行一对。 (Details ...)
rnd
- 从纯文本文件(Details ...)中随机选择一个条目
dbm
- 在 dbm 文件中查找包含名称,值对的条目。哈希是使用httxt2dbmUtil 从纯文本文件格式构造的。 (Details ...)
int
RewriteMap
提供的四个可用内部功能之一:toupper,tolower,escape 或 unescape。 (Details ...)
prg
- 调用外部程序或脚本来处理重写。 (Details ...)
dbd 或 fastdbd
- 要执行的 SQL SELECT 语句以查找重写目标。 (Details ...)
RewriteMap HowTo中提供了更多详细信息和大量示例。
RewriteOptions Directive
Description: | 为重写引擎设置一些特殊选项 |
---|---|
Syntax: | RewriteOptions Options |
Context: | 服务器配置,虚拟主机,目录,.htaccess |
Override: | FileInfo |
Status: | Extension |
Module: | mod_rewrite |
RewriteOptions
指令为当前的每服务器或每目录配置设置了一些特殊选项。 * Option *字符串当前只能是以下之一:
Inherit
- 这将强制当前配置继承父项的配置。在每个虚拟服务器上下文中,这意味着继承了主服务器的 Map,条件和规则。在每个目录的上下文中,这意味着父目录的
.htaccess
配置或<Directory>部分的条件和规则将被继承。继承的规则实际上被复制到使用此伪指令的部分。如果与本地规则结合使用,则继承的规则将被复制到本地规则之后。此指令的位置-低于或高于本地规则-对此行为没有影响。如果本地规则强制停止重写,则继承的规则将不被处理。
- 这将强制当前配置继承父项的配置。在每个虚拟服务器上下文中,这意味着继承了主服务器的 Map,条件和规则。在每个目录的上下文中,这意味着父目录的
Warning
从父范围继承的规则在子范围中指定的规则之后**应用。
InheritBefore
- 就像上面的
Inherit
一样,但父作用域中的规则在子作用域中指定的规则之前被应用。
在 Apache HTTP Server 2.3.10 和更高版本中可用。
- 就像上面的
InheritDown
- 如果启用此选项,则所有子配置都将继承当前配置的配置。等效于在所有子配置中指定
RewriteOptions Inherit
。有关如何处理父子关系的更多详细信息,请参见Inherit
选项。
在 Apache HTTP Server 2.4.8 和更高版本中可用。
- 如果启用此选项,则所有子配置都将继承当前配置的配置。等效于在所有子配置中指定
InheritDownBefore
- 就像上面的
InheritDown
一样,但是当前范围的规则在任何子范围中指定的规则之前被应用。
在 Apache HTTP Server 2.4.8 和更高版本中可用。
- 就像上面的
IgnoreInherit
- 该选项强制当前配置和子配置忽略所有从指定
InheritDown
或InheritDownBefore
的父代继承的规则。
在 Apache HTTP Server 2.4.8 和更高版本中可用。
- 该选项强制当前配置和子配置忽略所有从指定
AllowNoSlash
- 默认情况下,mod_rewrite将忽略 Map 到磁盘上目录但没有尾部斜杠的 URL,因为mod_dir模块将向 Client 端发出带有尾部斜杠的规范 URL 重定向。
当DirectorySlash指令设置为 off 时,可以启用AllowNoSlash
选项,以确保不再忽略重写规则。如果需要,可以使用此选项在与目录匹配的.htaccess 文件中应用重写规则,而不用斜杠。
在 Apache HTTP Server 2.4.0 和更高版本中可用。
AllowAnyURI
- 如果在
VirtualHost
或 httpd 2.2.22 或更高版本的服务器上下文中使用RewriteRule,则mod_rewrite仅在请求 URI 为URL-path时处理重写规则。这样可以避免某些安全问题,因为某些特定规则可能允许“令人惊讶”的模式扩展(请参阅CVE-2011-3368和CVE-2011-4317)。要解除对匹配 URL 路径的限制,可以启用AllowAnyURI
选项,并且mod_rewrite将规则集应用于任何请求 URI 字符串,无论该字符串是否与 HTTP 规范要求的 URL 路径语法匹配。
在 Apache HTTP Server 2.4.3 和更高版本中可用。
- 如果在
Security Warning
如果使用未经精心编写的重写规则,启用此选项将使服务器容易受到安全问题的影响。强烈建议不要使用此选项。尤其要提防包含'@
'字符的 Importing 字符串,这些字符串可能会根据上述 CVE 名称更改转换后的 URI 的解释。
MergeBase
- 使用此选项时,RewriteBase的值将从显式定义的位置复制到任何未定义自己的RewriteBase的子目录或子位置。这是 2.4.0 到 2.4.3 中的默认行为,并且可以使用 Apache HTTP Server 2.4.4 和更高版本来恢复该标志。
IgnoreContextInfo
- 在目录(htaccess)上下文中进行相对替换并且未设置RewriteBase时,此模块将使用一些扩展的 URL 和文件系统上下文信息将相对替换更改回 URL。 mod_userdir和mod_alias之类的模块提供了此扩展的上下文信息。在 2.4.16 及更高版本中可用。
LegacyPrefixDocRoot
- 在 2.4.26 之前,如果替换是与当前虚拟主机匹配的绝对 URL,则该 URL 可能首先被还原为 URL 路径,然后又被还原为本地路径。由于可以将 URL 简化为本地路径,因此该路径应以文档根作为前缀。当使用以下RewriteRule向 http:// host/file/myfile 发出请求时,这可以防止访问/ tmp/myfile 之类的文件。
RewriteRule /file/(.*) http://localhost/tmp/$1
此选项允许使用旧的行为,即文档根目录不以从 URL 简化的本地路径作为前缀。在 2.4.26 及更高版本中可用。
RewriteRule Directive
Description: | 定义重写引擎的规则 |
---|---|
Syntax: | RewriteRule Pattern Substitution [flags] |
Context: | 服务器配置,虚拟主机,目录,.htaccess |
Override: | FileInfo |
Status: | Extension |
Module: | mod_rewrite |
RewriteRule
指令是 true 的重写主力。该指令可以多次出现,每个实例定义一个重写规则。定义这些规则的 Sequences 很重要-这是它们在运行时应用的 Sequences。
Pattern是与 perl 兼容的regular expression。比较此模式所依据的内容取决于RewriteRule
指令的定义位置。
What is matched?
在VirtualHost上下文中,* Pattern *最初将与 URL 的主机名和端口之后,查询字符串之前的部分匹配(例如“ /app1/index.html”)。这是(%解码)URL-path。
在按目录的上下文中(Directory和.htaccess),* Pattern *仅与部分路径匹配,例如,对“ /app1/index.html”的请求可能与“ app1/index.html”进行比较,或者“ index.html”,具体取决于
RewriteRule
的定义位置。
在比较之前,将定义规则的目录路径从当前 Map 的文件系统路径中剥离(直到并包括尾斜杠)。逐目录前缀剥离的最终结果是,此上下文中的规则仅与定义规则的当前 Map 文件系统路径“以下”部分匹配。
诸如DocumentRoot和Alias之类的指令,甚至是先前RewriteRule
替换的结果,都确定当前 Map 的文件系统路径。
- 如果要与主机名,端口或查询字符串匹配,请分别使用RewriteCond和
%{HTTP_HOST}
,%{SERVER_PORT}
或%{QUERY_STRING}
变量。
Per-directory Rewrites
重写引擎可能会用在.htaccess个文件和<Directory>个部分中,但有些复杂。
要在这种情况下启用重写引擎,您需要设置“
RewriteEngine On
”和“Options FollowSymLinks
”必须启用。如果您的 Management 员已禁用对用户目录的FollowSymLinks
替代,则您将无法使用重写引擎。出于安全原因,此限制是必需的。有关将哪个前缀添加回相对替换的更多信息,请参见RewriteBase指令。
如果希望与每个目录(htaccess)RewriteRule 中的完整 URL 路径匹配,请在RewriteCond中使用
%{REQUEST_URI}
变量。删除的前缀始终以斜杠结尾,这意味着匹配永远不会以斜杠开头的字符串。因此,具有_的 Pattern *在每个目录上下文中都不会匹配。
尽管<Location>和<Files>部分(包括它们的正则表达式对应部分)在语法上允许重写规则,但这永远是不必要的,不受支持。在这些情况下可能 break 的 Feature 是相对替换。
If块遵循* directory *上下文的规则。
默认情况下,当merging sections属于同一上下文时,mod_rewrite 会覆盖规则。 RewriteOptions指令可以更改此行为,例如使用* Inherit *设置。
RewriteOptions还调节在配置的同一嵌套级别上声明的节的行为。在以下示例中,默认情况下,仅考虑第二个If块中声明的 RewriteRules,因为第一个被覆盖。使用RewriteOptions Inherit 强制 mod_rewrite 合并两个部分并考虑两组语句,而不是仅考虑最后一组。
<If "true">
# Without RewriteOptions Inherit, this rule is overridden by the next
# section and no redirect will happen for URIs containing 'foo'
RewriteRule foo http://example.com/foo [R]
</If>
<If "true">
RewriteRule bar http://example.com/bar [R]
</If>
有关regular expressions的一些提示,请参见mod_rewrite Introduction。
在mod_rewrite中,NOT 字符('!
')也可用作可能的模式前缀。这使您可以否定模式。例如:``如果当前 URL 不 不匹配此模式''。这可以用于 exceptions,在这种情况下更容易匹配否定模式,或用作最后的默认规则。
Note
当使用 NOT 字符取反一个模式时,您不能在该模式中包括分组的通配符部分。这是因为,如果模式不匹配(即,否定匹配),则组中没有内容。因此,如果使用否定的模式,则不能在替换字符串中使用$N
!
重写规则的Substitution是替换* Pattern *匹配的原始 URL 路径的字符串。 替代可以是:
file-system path
- 指定要传递给 Client 端的资源在文件系统上的位置。仅当在服务器(虚拟主机)上下文中配置了规则并且替换中路径的第一部分存在于文件系统中时,替换才被视为文件系统路径
URL-path
- 与要提供的资源的DocumentRoot相对路径。请注意,mod_rewrite会通过检查路径的第一段是否存在于文件系统的根目录中来猜测是指定了文件系统路径还是 URL 路径。例如,如果您指定
/www/file.html
的* Substitution 字符串,那么它将被视为 URL 路径除非*根目录或文件系统中存在名为www
的目录(或者,如果使用.htaccess
文件,相对于您的文档根目录),在这种情况下,它将被视为文件系统路径。如果希望将其他 URL Map 指令(例如Alias)应用于生成的 URL 路径,请使用[PT]
标志,如下所述。
- 与要提供的资源的DocumentRoot相对路径。请注意,mod_rewrite会通过检查路径的第一段是否存在于文件系统的根目录中来猜测是指定了文件系统路径还是 URL 路径。例如,如果您指定
Absolute URL
- 如果指定了绝对 URL,则mod_rewrite检查主机名是否与当前主机匹配。如果是这样,则将方案和主机名删除,并将得到的路径视为 URL 路径。否则,将对给定 URL 执行外部重定向。要强制将外部重定向回当前主机,请参见下面的
[R]
标志。
- 如果指定了绝对 URL,则mod_rewrite检查主机名是否与当前主机匹配。如果是这样,则将方案和主机名删除,并将得到的路径视为 URL 路径。否则,将对给定 URL 执行外部重定向。要强制将外部重定向回当前主机,请参见下面的
-
(破折号)- 破折号表示不应执行任何替换(现有路径未经修改地传递)。当需要在不更改路径的情况下应用标志(请参阅下文)时,将使用此方法。
除纯文本外,* Substitution *字符串还可以包括
对 RewriteRule 模式的反向引用(
$N
)向后引用(
%N
)到最后匹配的 RewriteCond 模式规则条件测试字符串(
%{VARNAME}
)中的服务器变量mapping-function个电话(
${mapname:key|default}
)
反向引用是格式为$
N ( N = 0..9)的标识符,它将由匹配的* Pattern 的第 N 组的内容替换。服务器变量与RewriteCond指令的 TestString *相同。Map 功能来自RewriteMap指令,并在此处进行了说明。这三种类型的变量按上述 Sequences 扩展。
重写规则按照在配置文件中定义的 Sequences 应用于以前的重写规则的结果。 URL 路径或文件系统路径(请参见上面的“匹配什么?”)已被* Substitution 完全替换*,重写过程将 continue 进行,直到应用了所有规则,或者被L flag或其他命令显式终止表示立即终止的标志,例如END
或F
。
Modifying the Query String
默认情况下,查询字符串不更改。但是,您可以在包含查询字符串部分的替换字符串中创建 URL。只需在替换字符串中使用问号来表示应将以下文本重新插入到查询字符串中。当您要删除现有的查询字符串时,仅用问号结束替换字符串。要组合新旧查询字符串,请使用[QSA]
标志。
另外,您可以通过将 [
* flags * ]
作为RewriteRule
指令的第三个参数附加来设置特殊的actions。 * Flags *是下表中任何标志的逗号分隔列表,用方括号括起来。 重写标志文件中提供了每个标志的更多详细信息和示例。
标志和语法 | Function | |
---|---|---|
B | 在应用转换之前,请在反向引用中转义非字母数字字符。 * details ... * | |
backrefnoplus|BNP | 如果要转义反向引用,则应将空格转义为%20 而不是。当在路径组件而不是查询字符串中使用反向引用时很有用。 * details ... * | |
chain|C | 规则链接到以下规则。如果规则失败,则链接到该规则的规则将被跳过。 * details ... * | |
cookie | CO = * NAME : VAL * | 在 Client 端浏览器中设置 cookie。完整语法为:CO = * NAME : VAL : domain * [:* lifetime * [:* path * [:* secure * [:* httponly *]]]] * details ... * |
discardpath|DPI | 导致重写的 URI 的 PATH_INFO 部分被丢弃。 * details ... * | |
END | 立即停止重写过程,不要再应用任何规则。还可以防止在每个目录和.htaccess 上下文中进一步执行重写规则。 (在 2.3.9 及更高版本中可用)* details ... * | |
env | E = [!] * VAR * [:* VAL *] | 导致设置环境变量* VAR (如果提供,则设置为值 VAL *)。表格 ! * VAR 导致未设置环境变量 VAR *。 * details ... * |
forbidden|F | 向 Client 端浏览器返回 403 FORBIDDEN 响应。 * details ... * | |
gone|G | 向 Client 端浏览器返回 410 GONE 响应。 * details ... * | |
Handler|H= Content-handler | 导致将结果 URI 发送到指定的* Content-handler *进行处理。 * details ... * | |
last|L | 立即停止重写过程,不要再应用任何规则。特别要注意每个目录和.htaccess 上下文的注意事项(另请参阅 END 标志)。 * details ... * | |
next|N | 重新运行重写过程,从第一个规则开始,以规则集的结果为起点。 * details ... * | |
nocase|NC | 使模式比较不区分大小写。 * details ... * | |
noescape|NE | 防止 mod_rewrite 在重写结果中应用特殊字符的十六进制转义。 * details ... * | |
nosubreq|NS | 如果当前请求是内部子请求,则导致规则被跳过。 * details ... * | |
proxy|P | 强制将替代 URL 作为代理请求在内部发送。 * details ... * | |
passthrough|PT | 强制将结果 URI 传递回 URL Map 引擎,以处理其他 URI 到文件名的翻译器,例如Alias 或Redirect 。 * details ... * |
|
qsappend|QSA | 将来自原始请求 URL 的任何查询字符串追加到在重写目标中创建的任何查询字符串。 * details ... * | |
qsdiscard|QSD | 丢弃所有附加到传入 URI 的查询字符串。 * details ... * | |
qslast|QSL | 将最后一个(最右边)问号解释为查询字符串定界符,而不是通常使用的第一个(最左边)问号。在 2.4.19 及更高版本中可用。 * details ... * | |
redirect|R[= code ] | 强制进行外部重定向,可以选择使用指定的 HTTP 状态代码。 * details ... * | |
skip|S= num | 告诉重写引擎如果当前规则匹配,则跳过下一个* num *规则。 * details ... * | |
type|T= MIME-type | 强制目标文件的MIME-type为指定的类型。 * details ... * |
Home directory expansion
当替换字符串以类似于“ /~user”的字符串开头(通过显式文本或反向引用)时,mod_rewrite将执行主目录扩展,而与mod_userdir的存在或配置无关。
当在RewriteRule指令上使用* PT *标志时,不会发生这种扩展。
以下是所有可能的替换组合及其含义:
内部每服务器配置(httpd.conf
)
对于请求```+567+`'':
Given Rule | Resulting Substitution |
---|---|
^/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/.htaccess
,其中RewriteBase "/somepath"
)
对于请求```+571+`'':**
Given Rule | Resulting Substitution |
---|---|
^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 |