Apache HTTP 服务器版本 2.5

本文档讨论 mod_rewrite 和 URL 匹配的一些技术细节。
Apache HTTP 服务器分多个阶段处理请求。在每个阶段, 一个或多个模块可能被调用来处理请求生命周期的那个部分。 这些阶段包括 URL 到文件名转换、身份验证、授权、内容和日志记录等。 (这不是一个详尽的列表。)
mod_rewrite 在其中两个阶段(或通常所说的"钩子")
中起作用,以影响 URL 的重写方式。
首先,它使用 URL 到文件名转换钩子,该钩子在 HTTP
请求被读取之后、但在任何授权开始之前触发。其次,它使用 Fixup 钩子,
该钩子在授权阶段之后、在目录级配置文件(.htaccess 文件)
被读取之后、但在内容处理程序被调用之前触发。
当请求进入并确定了对应的服务器或虚拟主机后,
重写引擎开始处理出现在服务器级配置中的所有 mod_rewrite
指令。(即在主服务器配置文件和 <Virtualhost> 配置段中。)
这发生在 URL 到文件名转换阶段。
几个步骤之后,一旦找到最终的数据目录,
就会应用目录级配置指令(.htaccess 文件和 <Directory> 块)。
这发生在 Fixup 阶段。
在每种情况下,mod_rewrite 都会将
REQUEST_URI 重写为新的 URL 或文件名。
在目录级上下文中(即在 .htaccess 文件和
Directory 块中),这些规则在 URL
已经被转换为文件名之后才被应用。因此,mod_rewrite
最初用来与 RewriteRule
指令进行比较的 URL 路径是转换后的完整文件系统路径,
其中当前目录路径(包括尾部斜杠)已从前面被移除。
举例来说:如果规则位于 /var/www/foo/.htaccess 中, 正在处理对 /foo/bar/baz 的请求,则表达式 ^bar/baz$ 将会匹配。
如果在目录级上下文中进行了替换,将使用新的 URL
发出新的内部子请求,重新开始请求阶段的处理。如果替换是相对路径,
RewriteBase
指令决定在替换前面添加的 URL 路径前缀。在目录级上下文中,
必须注意创建的规则最终(在未来某轮目录级重写处理中)不会执行替换,
以避免循环。(参见 RewriteLooping
以进一步讨论此问题。)
由于在目录级上下文中对 URL 进行了进一步操作, 你需要注意在该上下文中以不同方式编写重写规则。特别要记住, 前导目录路径将从你的重写规则所看到的 URL 中被去除。 请参考下面的示例以进一步说明。
| 规则位置 | 规则 |
|---|---|
| VirtualHost 配置段 | RewriteRule "^/images/(.+)\.jpg" "/images/$1.gif" |
| 文档根目录下的 .htaccess 文件 | RewriteRule "^images/(.+)\.jpg" "images/$1.gif" |
| images 目录下的 .htaccess 文件 | RewriteRule "^(.+)\.jpg" "$1.gif" |
要更深入地了解 mod_rewrite 如何在不同上下文中操作 URL,
你应该查阅重写期间生成的日志条目。
现在当 mod_rewrite 在这两个 API 阶段被触发时,
它从其配置结构中读取已配置的规则集(该配置结构在服务器级上下文中于启动时创建,
或在目录级上下文中于 Apache 内核的目录遍历过程中创建)。
然后使用包含的规则集(一条或多条规则及其条件)启动 URL 重写引擎。
URL 重写引擎本身的操作在两种配置上下文中完全相同。
只有最终结果的处理方式不同。
规则集中规则的顺序很重要,因为重写引擎以一种特殊的(且不太直观的)
顺序处理它们。规则如下:重写引擎逐条遍历规则集中的规则
(RewriteRule 指令),
当某条规则匹配时,它会可选地遍历对应的条件
(RewriteCond 指令)。由于历史原因,
条件写在前面,因此控制流程有点绕。参见图 1 了解更多细节。

图 1:重写规则集的控制流程
首先,URL 与每条规则的模式进行匹配。如果匹配失败,
mod_rewrite 立即停止处理该规则,并继续处理下一条规则。
如果模式匹配成功,mod_rewrite
会查找对应的规则条件(RewriteCond 指令,
在配置中紧接在 RewriteRule 之前出现)。
如果没有条件,则用从字符串替换构造的新值替换 URL,
并继续其规则循环。但如果存在条件,则启动一个内部循环,
按照条件列出的顺序处理它们。对于条件,逻辑是不同的:
我们不是将模式与当前 URL 匹配。而是首先通过展开变量、
反向引用、映射查找等来创建一个字符串 TestString,
然后尝试将 CondPattern 与之匹配。如果模式不匹配,
则整组条件和对应规则都失败。如果模式匹配,则处理下一个条件,
直到没有更多条件为止。如果所有条件都匹配,
则继续用替换替换 URL。