Apache HTTP 服务器版本 2.4
本文档是对 mod_rewrite
参考文档 的补充。它描述了 RewriteMap
指令的使用,并提供了各种 RewriteMap
类型的示例。
RewriteMap
指令定义了一个外部函数,可以在 RewriteRule
或 RewriteCond
指令的上下文中调用,以执行过于复杂或过于专门而无法仅通过正则表达式执行的重写操作。此查找的来源可以是下面各节中列出的任何类型,并在 RewriteMap
参考文档中列出。
RewriteMap
指令的语法如下
RewriteMap MapName MapType:MapSource
MapName 是您分配给映射的任意名称,您将在后面的指令中使用它。参数通过以下语法传递给映射
${
MapName :
LookupKey }
${
MapName :
LookupKey |
DefaultValue }
当出现这样的结构时,会查询映射 MapName 并查找键 LookupKey。如果找到键,则将映射函数结构替换为 SubstValue。如果未找到键,则将其替换为 DefaultValue,或者如果未指定 DefaultValue,则替换为空字符串。
例如,您可以定义一个 RewriteMap
如下
RewriteMap examplemap "txt:/path/to/file/map.txt"
然后,您可以在 RewriteRule
中使用此映射,如下所示
RewriteRule "^/ex/(.*)" "${examplemap:$1}"
如果在映射中找不到任何内容,可以指定一个默认值
RewriteRule "^/ex/(.*)" "${examplemap:$1|/not_found.html}"
RewriteMap
指令不能在 <Directory>
部分或 .htaccess
文件中使用。您必须在服务器或虚拟主机上下文中声明映射。创建映射后,您可以在这些范围内的 RewriteRule
和 RewriteCond
指令中使用它。您只是不能在这些范围内 **声明** 它。
以下各节描述了可使用的各种 MapType,并提供了每个类型的示例。
当使用 int
的 MapType 时,MapSource 是可用的内部 RewriteMap
函数之一。模块作者可以通过使用 ap_register_rewrite_mapfunc
API 注册它们来提供额外的内部函数。默认提供的函数是
要使用这些函数之一,请创建一个引用 int 函数的 RewriteMap
,然后在您的 RewriteRule
中使用它
将 URI 重定向到其全小写版本
RewriteMap lc int:tolower RewriteRule "(.*)" "${lc:$1}" [R]
请注意,这里提供的示例仅用于说明目的,并非建议。如果您想使 URL 不区分大小写,请考虑使用 mod_speling
代替。
当使用 txt
的 MapType 时,MapSource 是指向纯文本映射文件的系统路径,该文件每行包含一个空格分隔的键值对。可选地,一行可以包含一个注释,以 '#' 字符开头。
有效的文本重写映射文件将具有以下语法
# 注释行
MatchingKey SubstValue
MatchingKey SubstValue # 注释
当调用 RewriteMap
时,会在行中的第一个参数中查找参数,如果找到,则返回替换值。
例如,我们可以使用映射文件将产品名称转换为产品 ID,以便使用更易于记忆的 URL,使用以下方法
产品到 ID 配置
RewriteMap product2id "txt:/etc/apache2/productmap.txt" RewriteRule "^/product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]
我们假设这里的 prods.php
脚本知道在产品在查找映射中找不到时,它在收到 id=NOTFOUND
参数时该怎么做。
文件 /etc/apache2/productmap.txt
然后包含以下内容
##
## productmap.txt - 产品到 ID 映射文件
##
television 993
stereo 198
fishingrod 043
basketball 418
telephone 328
因此,当请求 http://example.com/product/television
时,将应用 RewriteRule
,并将请求在内部映射到 /prods.php?id=993
。
.htaccess
文件中使用它,则需要从重写模式中删除前导斜杠,以便它可以匹配任何内容RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]
查找的键由 httpd 缓存,直到映射文件的 mtime
(修改时间)更改或 httpd 服务器重新启动。这确保了对由许多请求调用的映射的更好性能。
当使用 rnd
的 MapType 时,MapSource 是指向纯文本映射文件的系统路径,该文件每行包含一个键,以及一个或多个由 |
分隔的值。如果匹配键,则将随机选择这些值之一。
例如,您可以使用以下映射文件和指令,通过反向代理在多个后端服务器之间提供随机负载均衡。图像将发送到“static”池中的一个服务器,而其他所有内容将发送到“dynamic”池中的一个服务器。
##
## map.txt -- 重写映射
##
static www1|www2|www3|www4
dynamic www5|www6
配置指令
RewriteMap servers "rnd:/path/to/file/map.txt" RewriteRule "^/(.*\.(png|gif|jpg))" "http://${servers:static}/$1" [NC,P,L] RewriteRule "^/(.*)" "http://${servers:dynamic}/$1" [P,L]
因此,当请求图像并匹配第一个规则时,RewriteMap
在映射文件中查找字符串 static
,该字符串将随机返回一个指定的 hostname,然后在 RewriteRule
目标中使用。
如果您希望更可能选择其中一个服务器(例如,如果其中一个服务器比其他服务器具有更多内存,因此可以处理更多请求),只需在映射文件中列出它更多次。
static www1|www1|www2|www3|www4
当使用 dbm
的 MapType 时,MapSource 是指向 DBM 数据库文件的系统路径,该文件包含要用于映射的键值对。这与 txt
映射的工作方式完全相同,但速度快得多,因为 DBM 是索引的,而文本文件不是。这允许更快地访问所需的键。
您可以选择指定特定的 dbm 类型
RewriteMap examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"
类型可以是 sdbm
、gdbm
、ndbm
或 db
。但是,建议您只使用与 Apache HTTP 服务器一起提供的 httxt2dbm 实用程序,因为它将使用正确的 DBM 库,与构建 httpd 时使用的库匹配。
要创建 dbm 文件,请首先创建一个文本映射文件,如 txt 部分所述。然后运行 httxt2dbm
$ httxt2dbm -i mapfile.txt -o mapfile.map
然后,您可以在 RewriteMap
指令中引用生成的 文件
RewriteMap mapname "dbm:/etc/apache/mapfile.map"
请注意,对于某些 dbm 类型,会生成多个文件,它们具有共同的基名。例如,您可能有两个名为 mapfile.map.dir
和 mapfile.map.pag
的文件。这是正常的,您只需要在 RewriteMap
指令中使用基名 mapfile.map
。
查找的键由 httpd 缓存,直到映射文件的 mtime
(修改时间)更改或 httpd 服务器重新启动。这确保了对由许多请求调用的映射的更好性能。
当使用 prg
的 MapType 时,MapSource 是指向可执行程序的系统路径,该程序将提供映射行为。这可以是已编译的二进制文件,也可以是解释语言(如 Perl 或 Python)中的程序。
此程序在 Apache HTTP 服务器启动时启动一次,然后通过 STDIN
和 STDOUT
与重写引擎通信。也就是说,对于每个映射函数查找,它都期望通过 STDIN
获取一个参数,并且应该在 STDOUT
上返回一个以换行符结尾的响应字符串。如果没有相应的查找值,映射程序应该返回四字符字符串“NULL
”以指示这一点。
如果定义的上下文没有将 RewriteEngine
设置为 on
,则不会启动外部重写程序。
默认情况下,外部重写程序以启动 httpd 的用户:组身份运行。这可以在 UNIX 系统上通过将用户名和组名作为第三个参数传递给 RewriteMap
来更改,格式为 username:groupname
。
此功能利用 rewrite-map
互斥锁,这是与程序可靠通信所必需的。互斥锁机制和锁定文件可以通过 Mutex
指令配置。
这里显示了一个简单的示例,它将请求 URI 中的所有连字符替换为下划线。
重写配置
RewriteMap d2u "prg:/www/bin/dash2under.pl" apache:apache RewriteRule "-" "${d2u:%{REQUEST_URI}}"
dash2under.pl
#!/usr/bin/perl $| = 1; # Turn off I/O buffering while (<STDIN>) { s/-/_/g; # Replace dashes with underscores print $_; }
$| = 1;
当然,这在其他语言中会有所不同。缓冲 I/O 会导致 httpd 等待输出,因此它会挂起。当使用 dbd
或 fastdbd
的 MapType 时,MapSource 是一个 SQL SELECT 语句,它接受一个参数并返回一个值。
mod_dbd
需要配置为指向正确的数据库,以便执行此语句。
此 MapType 有两种形式。使用 dbd
的 MapType 会导致在每次映射请求时执行查询,而使用 fastdbd
会在内部缓存数据库查找。因此,虽然 fastdbd
更有效,因此更快,但它不会在服务器重启之前获取数据库的更改。
如果查询返回多行,则使用结果集中的随机行。
RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s"
查询名称作为 SQL 预准备语句的标签传递给数据库驱动程序,因此需要遵循数据库所需的任何规则(例如大小写敏感性)。
RewriteMap
指令可以出现多次。对于每个映射函数,使用一个 RewriteMap
指令来声明其重写映射文件。
虽然你不能在每个目录上下文中**声明**映射(.htaccess
文件或 <Directory>
块),但可以在每个目录上下文中**使用**此映射。