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

使用 RewriteMap

可用语言:  en  |  fr 

本文档是对 mod_rewrite 参考文档 的补充。它描述了 RewriteMap 指令的使用,并提供了各种 RewriteMap 类型的示例。

请注意,许多示例在您的特定服务器配置中无法直接使用,因此您需要理解它们,而不仅仅是将示例复制粘贴到您的配置中。
Support Apache!

另请参阅

top

简介

RewriteMap 指令定义了一个外部函数,可以在 RewriteRuleRewriteCond 指令的上下文中调用,以执行过于复杂或过于专门而无法仅通过正则表达式执行的重写操作。此查找的来源可以是下面各节中列出的任何类型,并在 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}"

每个目录和 .htaccess 上下文

RewriteMap 指令不能在 <Directory> 部分或 .htaccess 文件中使用。您必须在服务器或虚拟主机上下文中声明映射。创建映射后,您可以在这些范围内的 RewriteRuleRewriteCond 指令中使用它。您只是不能在这些范围内 **声明** 它。

以下各节描述了可使用的各种 MapType,并提供了每个类型的示例。

top

int:内部函数

当使用 int 的 MapType 时,MapSource 是可用的内部 RewriteMap 函数之一。模块作者可以通过使用 ap_register_rewrite_mapfunc API 注册它们来提供额外的内部函数。默认提供的函数是

要使用这些函数之一,请创建一个引用 int 函数的 RewriteMap,然后在您的 RewriteRule 中使用它

将 URI 重定向到其全小写版本

RewriteMap lc int:tolower
RewriteRule "(.*)" "${lc:$1}" [R]

请注意,这里提供的示例仅用于说明目的,并非建议。如果您想使 URL 不区分大小写,请考虑使用 mod_speling 代替。

top

txt:纯文本映射

当使用 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 然后包含以下内容

产品到 ID 映射

##
## productmap.txt - 产品到 ID 映射文件
##

television 993
stereo 198
fishingrod 043
basketball 418
telephone 328

因此,当请求 http://example.com/product/television 时,将应用 RewriteRule,并将请求在内部映射到 /prods.php?id=993

注意:.htaccess 文件

给出的示例旨在用于服务器或虚拟主机范围。如果您计划在 .htaccess 文件中使用它,则需要从重写模式中删除前导斜杠,以便它可以匹配任何内容
RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

缓存查找

查找的键由 httpd 缓存,直到映射文件的 mtime(修改时间)更改或 httpd 服务器重新启动。这确保了对由许多请求调用的映射的更好性能。

top

rnd:随机纯文本

当使用 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

top

dbm:DBM 哈希文件

当使用 dbm 的 MapType 时,MapSource 是指向 DBM 数据库文件的系统路径,该文件包含要用于映射的键值对。这与 txt 映射的工作方式完全相同,但速度快得多,因为 DBM 是索引的,而文本文件不是。这允许更快地访问所需的键。

您可以选择指定特定的 dbm 类型

RewriteMap examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"

类型可以是 sdbmgdbmndbmdb。但是,建议您只使用与 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.dirmapfile.map.pag 的文件。这是正常的,您只需要在 RewriteMap 指令中使用基名 mapfile.map

缓存查找

查找的键由 httpd 缓存,直到映射文件的 mtime(修改时间)更改或 httpd 服务器重新启动。这确保了对由许多请求调用的映射的更好性能。

top

prg:外部重写程序

当使用 prg 的 MapType 时,MapSource 是指向可执行程序的系统路径,该程序将提供映射行为。这可以是已编译的二进制文件,也可以是解释语言(如 Perl 或 Python)中的程序。

此程序在 Apache HTTP 服务器启动时启动一次,然后通过 STDINSTDOUT 与重写引擎通信。也就是说,对于每个映射函数查找,它都期望通过 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 $_;
}

警告!

  • 保持你的重写映射程序尽可能简单。如果程序挂起,它会导致 httpd 无限期地等待来自映射的响应,进而导致 httpd 停止响应请求。
  • 确保在你的程序中关闭缓冲。在 Perl 中,这可以通过示例脚本中的第二行完成:$| = 1; 当然,这在其他语言中会有所不同。缓冲 I/O 会导致 httpd 等待输出,因此它会挂起。
  • 请记住,程序只有一个副本,在服务器启动时启动。所有请求都需要通过这个瓶颈。如果许多请求必须通过此过程,或者脚本本身非常慢,这会导致明显的减速。
top

dbd 或 fastdbd:SQL 查询

当使用 dbdfastdbd 的 MapType 时,MapSource 是一个 SQL SELECT 语句,它接受一个参数并返回一个值。

mod_dbd 需要配置为指向正确的数据库,以便执行此语句。

此 MapType 有两种形式。使用 dbd 的 MapType 会导致在每次映射请求时执行查询,而使用 fastdbd 会在内部缓存数据库查找。因此,虽然 fastdbd 更有效,因此更快,但它不会在服务器重启之前获取数据库的更改。

如果查询返回多行,则使用结果集中的随机行。

示例

RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s"

注意

查询名称作为 SQL 预准备语句的标签传递给数据库驱动程序,因此需要遵循数据库所需的任何规则(例如大小写敏感性)。

top

总结

RewriteMap 指令可以出现多次。对于每个映射函数,使用一个 RewriteMap 指令来声明其重写映射文件。

虽然你不能在每个目录上下文中**声明**映射(.htaccess 文件或 <Directory> 块),但可以在每个目录上下文中**使用**此映射。

可用语言:  en  |  fr 

top

评论

注意
这不是一个问答部分。此处放置的评论应指向有关改进文档或服务器的建议,如果它们被实施或被认为无效/偏离主题,可能会被我们的版主删除。有关如何管理 Apache HTTP Server 的问题应发送到我们的 IRC 频道 #httpd(在 Libera.chat 上)或发送到我们的 邮件列表