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

使用 mod_rewrite 的高级技巧

可用语言:  en  |  fr 

本文档是对 mod_rewrite 参考文档 的补充。它提供了一些使用 mod_rewrite 的高级技巧。

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

另请参阅

top

基于 URL 的跨多个后端的碎片化

描述

一种常见的用于分发服务器负载或存储空间的方法称为“碎片化”。使用这种方法时,前端服务器将使用 URL 一致地将用户或对象“碎片化”到不同的后端服务器。

解决方案

从用户到目标服务器的映射保存在外部映射文件中。它们看起来像

user1 physical_host_of_user1
user2 physical_host_of_user2
# ... 等等

我们将此放入一个名为 map.users-to-hosts 的文件中。目标是映射;

/u/user1/anypath

http://physical_host_of_user1/u/user/anypath

因此,每个 URL 路径不需要在每个后端物理主机上都有效。以下规则集在映射文件的帮助下实现了这一点,假设 server0 是一个默认服务器,如果用户在映射中没有条目,则将使用该服务器

RewriteEngine on
RewriteMap    users-to-hosts      "txt:/path/to/map.users-to-hosts"
RewriteRule   "^/u/([^/]+)/?(.*)" "http://${users-to-hosts:$1|server0}/u/$1/$2"

有关此指令语法的更多讨论,请参阅 RewriteMap 文档和 RewriteMap 如何操作

top

动态内容生成

描述

我们希望动态生成内容,但在生成后静态存储它。此规则将检查静态文件是否存在,如果不存在,则生成它。如果需要,可以定期删除静态文件(例如,通过 cron),并在需要时重新生成。

解决方案
这是通过以下规则集完成的
# This example is valid in per-directory context only
RewriteCond "%{REQUEST_URI}"   "!-U"
RewriteRule "^(.+)\.html$"     "/regenerate_page.cgi"   [PT,L]

-U 运算符确定测试字符串(在本例中为 REQUEST_URI)是否为有效的 URL。它通过子请求来完成此操作。如果此子请求失败 - 也就是说,请求的资源不存在 - 此规则将调用 CGI 程序 /regenerate_page.cgi,该程序生成请求的资源并将其保存到文档目录中,以便下次请求时,可以提供静态副本。

通过这种方式,可以以静态形式提供很少更新的文档。如果需要刷新文档,可以从文档目录中删除它们,然后在下一次请求时重新生成它们。

top

负载均衡

描述

我们希望使用 mod_rewrite 将负载随机分配到多个服务器。

解决方案

我们将使用 RewriteMap 和服务器列表来完成此操作。

RewriteEngine on
RewriteMap lb        "rnd:/path/to/serverlist.txt"
RewriteRule "^/(.*)" "http://${lb:servers}/$1"     [P,L]

serverlist.txt 将包含服务器列表

## serverlist.txt

servers one.example.com|two.example.com|three.example.com

如果您希望某台特定服务器比其他服务器承担更多负载,请在列表中添加它多次。

讨论

Apache 带有一个负载均衡模块 - mod_proxy_balancer - 它比使用 mod_rewrite 拼凑出来的任何东西都要灵活和功能强大。

top

结构化用户目录

描述

一些拥有数千个用户的网站使用结构化的主目录布局, 每个主目录都在一个子目录中,该子目录以用户名首字母开头(例如)。因此,/~larry/anypath/home/l/larry/public_html/anypath,而 /~waldo/anypath/home/w/waldo/public_html/anypath

解决方案

我们使用以下规则集将波浪号 URL 扩展到上述布局。

RewriteEngine on
RewriteRule   "^/~(([a-z])[a-z0-9]+)(.*)"  "/home/$2/$1/public_html$3"
top

重定向锚点

描述

默认情况下,重定向到 HTML 锚点不起作用,因为 mod_rewrite 会转义 # 字符,将其变成 %23。这反过来又会破坏重定向。

解决方案

RewriteRule 上使用 [NE] 标志。NE 代表 No Escape(不转义)。

讨论
此技巧当然也适用于其他特殊字符,mod_rewrite 默认情况下会对这些字符进行 URL 编码。
top

时间相关的重写

描述

我们希望使用 mod_rewrite 根据一天中的时间提供不同的内容。

解决方案

有很多名为 TIME_xxx 的变量用于重写条件。结合特殊的词典比较模式 <STRING>STRING=STRING,我们可以进行时间相关的重定向

RewriteEngine on
RewriteCond   "%{TIME_HOUR}%{TIME_MIN}" ">0700"
RewriteCond   "%{TIME_HOUR}%{TIME_MIN}" "<1900"
RewriteRule   "^foo\.html$"             "foo.day.html" [L]
RewriteRule   "^foo\.html$"             "foo.night.html"

这将在 07:01-18:59 时间段内在 URL foo.html 下提供 foo.day.html 的内容,而在剩余时间内提供 foo.night.html 的内容。

mod_cache、中间代理和浏览器都可能缓存响应并导致在配置的时间窗口之外显示任一页面。可以使用 mod_expires 来控制这种效果。当然,您最好直接动态提供内容,并根据一天中的时间对其进行自定义。
top

根据 URL 部分设置环境变量

描述

有时,我们希望在执行重写时维护某种状态。例如,您想记录您已经执行了该重写,以便以后可以检查请求是否通过该重写而来。一种方法是设置环境变量。

解决方案

使用 [E] 标志设置环境变量。

RewriteEngine on
RewriteRule   "^/horse/(.*)"   "/pony/$1" [E=rewritten:1]

稍后在您的规则集中,您可以使用 RewriteCond 检查此环境变量

RewriteCond "%{ENV:rewritten}" "=1"

请注意,环境变量不会在外部重定向中保留。您可以考虑使用 [CO] 标志设置 cookie。对于每个目录和 htaccess 重写,其中最终替换被处理为内部重定向,来自上一轮重写的环境变量将以“REDIRECT_”为前缀。

可用语言:  en  |  fr 

top

评论

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