Apache mod_rewrite 简介

本文档是对mod_rewrite reference documentation的补充。它描述了使用mod_rewrite所必需的基本概念。其他文档也有更详细的介绍,但是此文档应该可以帮助 Starters 入门。

Introduction

Apache 模块mod_rewrite是一个功能非常强大且复杂的模块,它提供了一种进行 URL 操作的方法。有了它,您几乎可以完成可能需要的所有类型的 URL 重写。但是,它有些复杂,可能会对 Starters 造成威胁。还有一种趋向于将重写规则视为魔术,在不 true 理解其作用的情况下使用它们。

本文试图提供足够的背景知识,以便理解以下内容,而不是盲目地复制。

请记住,许多常见的 URL 操作任务并不需要mod_rewrite的全部功能和复杂性。有关简单的任务,请参见mod_alias将 URL Map 到文件系统上的文档。

最后,在 continue 之前,请确保使用LogLevel指令将mod_rewrite的日志级别配置为跟踪级别之一。尽管这可以提供大量信息,但是在调试mod_rewrite配置问题时它是必不可少的,因为它将准确告诉您每个规则的处理方式。

Regular Expressions

mod_rewrite使用Perl 兼容的正则表达式词汇表。在本文档中,我们不尝试提供对正则表达式的详细参考。为此,我们推荐PCRE 手册页Perl 正则表达式手册页掌握正则表达式,Jeffrey Friedl 着

在本文档中,我们尝试提供足够的正则表达式词汇表,以助您入门而又不失为一个理想的选择,希望RewriteRule是科学公式,而不是魔咒。

Regex vocabulary

以下是编写正则表达式和RewriteRule所需的最小构建块。它们当然不能代表完整的正则表达式词汇,但是它们是一个很好的起点,应该可以帮助您阅读基本的正则表达式以及编写自己的正则表达式。

CharacterMeaningExample
.匹配任何单个字符c.t将与catcotcut等匹配
+重复上一场 match 一次或多次a+匹配aaaaaa
*重复上一次匹配零次或多次a*匹配所有相同的事物a+匹配,但还将匹配一个空字符串
?使 match 成为可选colou?r将匹配colorcolour
\转义下一个字符\.将匹配.(点),而不是任何单个字符,如上所述
^称为锚,匹配字符串的开头^a匹配以a开头的字符串
$另一个锚点,它匹配字符串的结尾a$匹配以a结尾的字符串
( )将几个字符分组为一个单元,并捕获一个匹配项以用于向后引用中(ab)+ababab匹配-即+适用于该组。有关反向引用的更多信息,请参见below
[ ]字符类-匹配字符之一c[uoa]t匹配cutcotcat
[^ ]负字符类-匹配未指定的任何字符c[^/]t匹配catc=t,但不匹配c/t

mod_rewrite中,可以在正则表达式之前使用!字符将其取反。也就是说,仅当字符串与表达式的其余部分不匹配时,才认为字符串已匹配。

正则表达式后向引用可用性

这里要记住的一件事很重要:每当在* Pattern CondPattern 之一中使用括号时,内部都会创建反向引用,该反向引用可与字符串$N%N一起使用(请参见下文)。这些可用于创建RewriteRule Substitution 参数或RewriteCond TestString *参数。

RewriteRule模式中的捕获(违反直觉)可用于所有前面的RewriteCond指令,因为RewriteRule表达式是在各个条件之前求值的。

图 1 显示了将反向引用扩展到哪个位置,并说明了 RewriteRule,RewriteCond 匹配的流程。在下一章中,我们将探索如何使用这些反向引用,因此,如果一开始对您似乎有些陌生,请不要担心。

RewriteRule 和  RewriteCond 匹配的流程

图 1:规则的反向引用流程。
在此示例中,对/test/1234的请求将转换为/admin.foo?page=test&id=1234&host=admin.example.com

RewriteRule Basics

RewriteRule由以空格分隔的三个参数组成。参数是

  • 模式:规则应影响哪些传入 URL;

  • 替代:匹配的请求应该发送到哪里;

  • [标志]:影响重写请求的选项。

模式是regular expression。它最初(对于第一个重写规则或直到发生替换)与传入请求的 URL 路径(主机名之后但在任何表示查询字符串开头的问号之前的部分)匹配,或者在每个目录中匹配上下文,相对于相对于定义规则的目录的请求路径。替换发生后,将遵循的规则与替换值进行匹配。

RewriteRule 指令的语法

图 2:RewriteRule 指令的语法。

替换本身可以是三件事之一:

  • 资源的完整文件系统路径
RewriteRule "^/games" "/usr/local/games/web"

这会将请求 Map 到文件系统上的任意位置,就像Alias指令一样。

  • 资源的网络路径
RewriteRule "^/foo$" "/bar"

如果DocumentRoot设置为/usr/local/apache2/htdocs,那么此伪指令会将http://example.com/foo的请求 Map 到路径/usr/local/apache2/htdocs/bar

  • 绝对网址
RewriteRule "^/product/view$" "http://site2.example.com/seeproduct.html" [R]

这告诉 Client 端对指定的 URL 发出新请求。

替换还可以包含对模式所匹配的传入 URL 路径部分的“反向引用”。考虑以下:

RewriteRule "^/product/(.*)/view$" "/var/web/productdb/$1"

变量$1将替换为 Pattern 中括号内的表达式所匹配的任何文本。例如,对http://example.com/product/r14df/view的请求将 Map 到路径/var/web/productdb/r14df

如果括号中有多个表达式,则它们按 Sequences 在变量$1$2$3等中可用。

Rewrite Flags

RewriteRule的行为可以通过在规则末尾应用一个或多个标志来进行修改。例如,可以通过应用[NC]标志使规则的匹配行为不区分大小写:

RewriteRule "^puppy.html" "smalldog.html" [NC]

有关可用标志,其含义和示例的更多详细信息,请参见Rewrite Flags文档。

Rewrite Conditions

可以使用一个或多个RewriteCond指令来限制将受以下RewriteRule约束的请求的类型。第一个参数是描述请求 Feature 的变量,第二个参数是必须与变量匹配的regular expression,第三个可选参数是标志列表,这些标志修改了评估匹配的方式。

RewriteCond 指令的语法

图 3:RewriteCond 指令的语法

例如,要将所有请求从特定 IP 范围发送到其他服务器,可以使用:

RewriteCond "%{REMOTE_ADDR}" "^10\.2\."
RewriteRule "(.*)"           "http://intranet.example.com$1"

如果指定多个RewriteCond,则它们必须全部匹配才能应用RewriteRule。例如,要拒绝查询字符串中包含单词“ hack”的请求,除非它们还包含包含单词“ go”的 cookie,则可以使用:

RewriteCond "%{QUERY_STRING}" "hack"
RewriteCond "%{HTTP_COOKIE}"  !go
RewriteRule "."               "-"   [F]

请注意,感叹号指定了否定匹配,因此仅当 cookie 不包含“ go”时才应用该规则。

RewriteCond s 中包含的正则表达式中的匹配项可以使用%1%2等变量用作RewriteRule中 Substitution 的一部分。例如,这将根据用于访问服务器的主机名将请求定向到其他目录。site:

RewriteCond "%{HTTP_HOST}" "(.*)"
RewriteRule "^/(.*)"       "/sites/%1/$1"

如果请求是针对http://example.com/foo/bar,则%1将包含example.com,而$1将包含foo/bar

Rewrite maps

RewriteMap伪指令提供了一种调用外部函数的方法,可以这么说,它可以为您进行重写。 RewriteMap 补充文档中对此进行了更详细的讨论。

.htaccess files

重写通常在主服务器配置设置中(在任何<Directory>部分之外)或在<VirtualHost>个容器中进行配置。这是最简单的重写方法,建议您这样做。但是,可以在<Directory>部分或.htaccess files内部进行重写,但要付出一些额外的复杂性。此技术称为按目录重写。

每个服务器重写的主要区别在于,包含.htaccess文件的目录的路径前缀在匹配RewriteRule之前被除去。此外,应使用RewriteBase来确保正确 Map 请求。