On this page
Apache mod_rewrite 技术细节
本文档讨论了 mod_rewrite 和 URL 匹配的一些技术细节。
API Phases
Apache HTTP Server 分几个阶段处理请求。在这些阶段的每个阶段,可以调用一个或多个模块来处理请求生命周期的这一部分。阶段包括 URL 到文件名的转换,身份验证,授权,内容和日志记录。 (这不是详尽的 Lists.)
mod_rewrite 在这两个阶段(或经常被称为“钩子”)中起作用,以影响 URL 的重写方式。
首先,它使用 URL 到文件名转换钩子,该钩子在读取 HTTP 请求之后但开始任何授权之前发生。其次,它使用 Fixup 钩子,该钩子在授权阶段之后,在读取每个目录的配置文件(.htaccess
文件)之后,但在调用内容处理程序之前。
因此,在请求进入并确定了相应的服务器或虚拟主机之后,重写引擎将开始处理每个服务器配置中出现的任何mod_rewrite
指令。 (即在主服务器配置文件和<Virtualhost>部分中。)这发生在 URL 到文件名阶段。
几步后,一旦找到最终的数据目录,就应用每个目录的配置指令(.htaccess
文件和<Directory>块)。这发生在修复阶段。
在每种情况下,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 的开头目录路径。请考虑以下示例以进一步说明。
规则位置 | Rule |
---|---|
VirtualHost section | RewriteRule“ ^/images /(。\。jpg”“” /images/$1.gif“ |
文件根目录中的.htaccess 文件 | RewriteRule“ ^ images /(。\。jpg”“” images/$ 1.gif“ |
.htaccess 文件在图像目录中 | RewriteRule“ ^(.)\。jpg”“ $ 1.gif” |
要进一步了解 mod_rewrite 如何在不同上下文中操纵 URL,您应该查阅在重写期间制作的log entries。
Ruleset Processing
现在,当在这两个 API 阶段中触发 mod_rewrite 时,它将从其配置结构中读取已配置的规则集(该规则集本身是在针对每个服务器上下文启动时创建的,或者是针对每个目录上下文在 Apache 内核的目录遍历期间创建的)。然后,使用包含的规则集(一个或多个规则及其条件)启动 URL 重写引擎。对于两个配置上下文,URL 重写引擎本身的操作是完全相同的。仅最终结果处理有所不同。
规则集中规则的 Sequences 很重要,因为重写引擎以特殊(但不是很明显)的 Sequences 处理它们。规则是这样的:重写引擎按规则(RewriteRule指令)遍历规则集规则,并且当特定规则匹配时,可选地通过现有的相应条件(RewriteCond
指令)遍历。由于历史原因,首先要给出条件,因此控制流程有些冗长。有关更多详细信息,请参见图 1.
图 1:重写规则集的控制流
首先,URL 与每个规则的* Pattern 相匹配。如果失败,则 mod_rewrite 立即停止处理此规则,并 continue 执行下一个规则。如果 Pattern 匹配,则 mod_rewrite 查找相应的规则条件(RewriteCond 伪指令,出现在配置中 RewriteRule 的正上方)。如果不存在,则将 URL 替换为新值,该新值由字符串 Substitution 构造而成,并 continue 其规则循环。但是,如果条件存在,它将启动一个内部循环以按列出的 Sequences 对其进行处理。对于条件,逻辑是不同的:我们没有将模式与当前 URL 匹配。相反,我们首先通过扩展变量,反向引用,Map 查找, etc. 创建字符串 TestString ,然后尝试将 CondPattern 与之匹配。如果模式不匹配,则完整的条件集和相应的规则将失败。如果模式匹配,则处理下一个条件,直到没有其他条件可用为止。如果所有条件都匹配,则 continue 处理,用 Substitution *替换 URL。