<-
Apache > HTTP 服务器 > 文档 > 版本 2.4 > 重写

Apache mod_rewrite 简介

可用语言:  en  |  fr 

本文档是对 mod_rewrite 参考文档 的补充。它描述了使用 mod_rewrite 所需的基本概念。其他文档将更详细地介绍,但本文档应该可以帮助初学者入门。

Support Apache!

另请参阅

top

简介

Apache 模块 mod_rewrite 是一个非常强大且复杂的模块,它提供了一种执行 URL 操作的方法。使用它,您可以执行几乎所有类型的 URL 重写,这些重写可能是您需要的。但是,它有些复杂,对于初学者来说可能令人生畏。还有一种趋势是将重写规则视为魔术咒语,在不真正了解它们的作用的情况下使用它们。

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

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

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

top

正则表达式

mod_rewrite 使用 Perl 兼容正则表达式 词汇。在本文件中,我们不会尝试提供正则表达式的详细参考。为此,我们推荐 PCRE 手册页Perl 正则表达式手册页Mastering Regular Expressions,作者:Jeffrey Friedl

在本文件中,我们试图提供足够的正则表达式词汇,以帮助您入门,而不是让您不知所措,希望 RewriteRule 成为科学公式,而不是魔术咒语。

正则表达式词汇

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

字符 含义 示例
. 匹配任何单个字符 c.t 将匹配 catcotcut
+ 重复前一个匹配项一次或多次 a+ 匹配 aaaaaa
* 重复前一个匹配项零次或多次 a* 匹配与 a+ 匹配的相同内容,但也会匹配空字符串
? 使匹配项可选 colou?r 将匹配 colorcolour
\ 转义下一个字符 \. 将匹配 .(点),而不是如上所述的任何单个字符
^ 称为锚点,匹配字符串的开头 ^a 匹配以 a 开头的字符串
$ 另一个锚点,它匹配字符串的结尾 a$ 匹配以 a 结尾的字符串
( ) 将多个字符分组为一个单元,并捕获匹配项以供反向引用使用 (ab)+ 匹配 ababab - 也就是说,+ 应用于该组。有关反向引用的更多信息,请参阅 下面
[ ] 字符类 - 匹配其中一个字符 c[uoa]t 匹配 cutcotcat
[^ ] 否定字符类 - 匹配任何未指定的字符 c[^/]t 匹配 catc=t,但不匹配 c/t

mod_rewrite 中,! 字符可以在正则表达式之前使用以否定它。也就是说,只有当字符串不匹配表达式的其余部分时,才会认为它已匹配。

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

这里有一点需要注意:无论何时在模式或其中一个CondPattern 中使用括号,都会创建内部反向引用,这些反向引用可以使用字符串 $N%N(见下文)使用。这些可用于创建 RewriteRule替换参数或 RewriteCond测试字符串参数。

RewriteRule 模式中的捕获(反直觉地)可用于所有前面的 RewriteCond 指令,因为 RewriteRule 表达式在各个条件之前进行评估。

图 1 显示了反向引用被传输到哪些位置以进行扩展,以及说明了 RewriteRule、RewriteCond 匹配的流程。在接下来的章节中,我们将探讨如何使用这些反向引用,所以如果一开始看起来有点陌生,请不要担心。

Flow of RewriteRule and RewriteCond matching
图 1: 通过规则的反向引用流。
在此示例中,对 /test/1234 的请求将被转换为 /admin.foo?page=test&id=1234&host=admin.example.com

top

RewriteRule 基础

一个 RewriteRule 由三个用空格分隔的参数组成。这些参数是

  1. 模式:哪些传入 URL 应该受该规则影响;
  2. 替换:匹配的请求应该发送到哪里;
  3. [标志]:影响重写请求的选项。

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

Syntax of the RewriteRule directive
图 2: RewriteRule 指令的语法。

替换 本身可以是以下三种情况之一

1. 资源的完整文件系统路径
RewriteRule "^/games" "/usr/local/games/web/puzzles.html"

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

2. 资源的 Web 路径
RewriteRule "^/games$" "/puzzles.html"

如果 DocumentRoot 设置为 /usr/local/apache2/htdocs,则此指令将把对 http://example.com/games 的请求映射到路径 /usr/local/apache2/htdocs/puzzles.html

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

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

请注意,12 的语法完全相同。它们之间的区别在于,在 1 的情况下,目标路径的顶层(即 /usr/)存在于文件系统上,而在 2 的情况下,它不存在。(即,文件系统中没有 /bar/ 作为根级目录。)

替换 还可以包含对传入 URL 路径中由 模式 匹配的部分的反向引用。考虑以下内容

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

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

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

top

重写标志

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

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

有关可用标志、它们的含义和示例的更多详细信息,请参阅 重写标志 文档。

top

重写条件

一个或多个 RewriteCond 指令可用于限制将受以下 RewriteRule 影响的请求类型。第一个参数是描述请求特征的变量,第二个参数是必须与变量匹配的 正则表达式,第三个可选参数是修改匹配评估方式的标志列表。

Syntax of the RewriteCond directive
图 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 中包含的正则表达式中的匹配项可以使用变量 %1%2 等作为 RewriteRule 中的 替换 的一部分。例如,这将根据用于访问站点的 hostname 将请求定向到不同的目录

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

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

top

重写映射

RewriteMap 指令提供了一种调用外部函数的方法,可以这么说,以执行您的重写操作。这在 RewriteMap 补充文档 中有更详细的讨论。

top

.htaccess 文件

重写通常在主服务器配置设置(在任何 <Directory> 部分之外)或在 <VirtualHost> 容器内配置。这是执行重写的最简单方法,建议使用。但是,可以在 <Directory> 部分或 .htaccess 文件 中执行重写,但代价是会增加一些复杂性。这种技术称为每个目录重写。

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

可用语言:  en  |  fr 

top

评论

注意
这不是问答区。此处发布的评论应针对改进文档或服务器的建议,如果这些建议已被实施或被认为无效/偏离主题,则可能被我们的版主删除。有关如何管理 Apache HTTP Server 的问题,请咨询我们的 IRC 频道 #httpd(在 Libera.chat 上),或发送到我们的邮件列表