<-
Apache > HTTP 服务器 > 文档 > 版本 2.5 > Rewrite

Apache mod_rewrite 技术细节

可用语言:  de  |  en  |  es  |  fr  |  ja  |  ko  |  tr  |  zh-cn 

本文档讨论 mod_rewrite 和 URL 匹配的一些技术细节。

参见

top

API 阶段

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, 你应该查阅重写期间生成的日志条目

top

规则集处理

现在当 mod_rewrite 在这两个 API 阶段被触发时, 它从其配置结构中读取已配置的规则集(该配置结构在服务器级上下文中于启动时创建, 或在目录级上下文中于 Apache 内核的目录遍历过程中创建)。 然后使用包含的规则集(一条或多条规则及其条件)启动 URL 重写引擎。 URL 重写引擎本身的操作在两种配置上下文中完全相同。 只有最终结果的处理方式不同。

规则集中规则的顺序很重要,因为重写引擎以一种特殊的(且不太直观的) 顺序处理它们。规则如下:重写引擎逐条遍历规则集中的规则 (RewriteRule 指令), 当某条规则匹配时,它会可选地遍历对应的条件 (RewriteCond 指令)。由于历史原因, 条件写在前面,因此控制流程有点绕。参见图 1 了解更多细节。

RewriteRule 和 RewriteCond 匹配流程
图 1:重写规则集的控制流程

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

可用语言:  de  |  en  |  es  |  fr  |  ja  |  ko  |  tr  |  zh-cn