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_rewritetrace1trace8日志级别提供其操作的详细日志记录。可以使用LogLevel指令专门为mod_rewrite设置日志级别:直到级别debug,都不会记录任何操作,而trace8表示实际上已记录了所有操作。

Note

mod_rewrite使用较高的跟踪日志级别将大大降低 Apache HTTP Server 的速度!使用高于trace2的日志级别仅用于调试!

Example

LogLevel alert rewrite:trace3

RewriteLog

那些熟悉mod_rewrite早期版本的人无疑会在寻找RewriteLogRewriteLogLevel指令。上面提到的新的每模块日志记录配置已完全取代了此功能。

要仅获取特定于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)上下文中的替换中使用相对路径时,此指令是“必需的”,除非满足以下任一条件:

在下面的示例中,由于资源与文档根目录无关,因此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 的当前状态都匹配其模式时才使用以下规则,如果满足这些条件,则

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 分别取决于UseCanonicalNameUseCanonicalPhysicalPort的值。

mod_rewrite特殊的内容包括以下内容。

如果* TestString 具有特殊值expr,则 CondPattern *将被视为ap_expr。如果未提供novary标志,则表达式中引用的 HTTP Headers 将添加到 Vary Headers 中。

您应该注意的其他事项:

如果发生替换并且重写 continue,则两个变量的值将相应更新。

如果用于每个服务器的上下文(,即,在将请求 Map 到文件系统之前),则 SCRIPT_FILENAME 和 REQUEST_FILENAME 不能包含完整的本地文件系统路径,因为在此处理阶段该路径未知。在这种情况下,两个变量最初都将包含 REQUEST_URI 的值。为了在每个服务器上下文中获取请求的完整本地文件系统路径,请使用基于 URL 的前瞻%{LA-U:REQUEST_FILENAME}来确定 REQUEST_FILENAME 的最终值。

如果在条件中使用 HTTP Headers,则该条件将被添加到响应的 Vary Headers 中,以防条件对请求的评估为 true。如果条件对于请求的评估结果为 false,则“不”添加。为了适当地缓存,需要将 HTTP Headers 添加到响应的 Vary Headers 中。

必须记住,在“ ornext|OR ”标志的情况下,条件遵循短路逻辑,因此可能根本无法评估某些条件。

例如,要根据每个服务器上下文(httpd.conf文件)中的REMOTE_USER变量进行重写,您必须使用%{LA-U:REMOTE_USER}-此变量是由授权阶段设置的,授权阶段在 URL 转换阶段之后(在mod_rewrite操作期间) 。

另一方面,由于mod_rewrite通过 API 的 Fixup 阶段实现了其按目录的上下文(.htaccess文件),并且由于授权阶段在此阶段之前*进行,所以您只能在该上下文中使用%{REMOTE_USER}

Note

字符串比较运算符是* CondPattern *参数的一部分,如果使用了引号,则必须将其包括在引号中。例如。

RewriteCond %{HTTP_USER_AGENT} "=This Robot/1.0"

此标志返回有关访问控制,身份验证和授权之类的信息。该标志返回有关已配置处理程序(静态文件,CGI,代理等)将返回的状态代码的信息。

For example:

RewriteCond /var/www/%{REQUEST_URI} !-f
RewriteRule ^(.+) /other/archive/$1 [R]

在下面的示例中,-strmatch用于将REFERER与站点主机名进行比较,以阻止不需要的热链接。

RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://%{HTTP_HOST}/*'"
RewriteRule "^/images" "-" [F]

您还可以通过将 [ * flags * ] 作为RewriteCond指令的第三个参数添加,来为* CondPattern 设置特殊标志,其中 flags *是以下任意标志的逗号分隔列表:

RewriteCond "%{REMOTE_HOST}"  "^host1"  [OR]
RewriteCond "%{REMOTE_HOST}"  "^host2"  [OR]
RewriteCond "%{REMOTE_HOST}"  "^host3"
RewriteRule ...some special stuff for any of these hosts...

没有此标志,您将必须写入条件/规则对三遍。

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}"

可以使用* MapType MapSource *的以下组合:

RewriteMap HowTo中提供了更多详细信息和大量示例。

RewriteOptions Directive

Description: 为重写引擎设置一些特殊选项
Syntax: RewriteOptions Options
Context: 服务器配置,虚拟主机,目录,.htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

RewriteOptions指令为当前的每服务器或每目录配置设置了一些特殊选项。 * Option *字符串当前只能是以下之一:

Warning

从父范围继承的规则在子范围中指定的规则之后**应用。

DirectorySlash指令设置为 off 时,可以启用AllowNoSlash选项,以确保不再忽略重写规则。如果需要,可以使用此选项在与目录匹配的.htaccess 文件中应用重写规则,而不用斜杠。
在 Apache HTTP Server 2.4.0 和更高版本中可用。

Security Warning

如果使用未经精心编写的重写规则,启用此选项将使服务器容易受到安全问题的影响。强烈建议不要使用此选项。尤其要提防包含'@'字符的 Importing 字符串,这些字符串可能会根据上述 CVE 名称更改转换后的 URI 的解释。

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 文件系统路径“以下”部分匹配。

诸如DocumentRootAlias之类的指令,甚至是先前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 路径的字符串。 替代可以是:

除纯文本外,* Substitution *字符串还可以包括

反向引用是格式为$ N ( N = 0..9)的标识符,它将由匹配的* Pattern 的第 N 组的内容替换。服务器变量与RewriteCond指令的 TestString *相同。Map 功能来自RewriteMap指令,并在此处进行了说明。这三种类型的变量按上述 Sequences 扩展。

重写规则按照在配置文件中定义的 Sequences 应用于以前的重写规则的结果。 URL 路径或文件系统路径(请参见上面的“匹配什么?”)已被* Substitution 完全替换*,重写过程将 continue 进行,直到应用了所有规则,或者被L flag或其他命令显式终止表示立即终止的标志,例如ENDF

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 到文件名的翻译器,例如AliasRedirect。 * 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
首页