Apache HTTP 服务器版本 2.4
本文档是对 mod_rewrite
参考文档 的补充。它提供了一些使用 mod_rewrite 的高级技巧。
一种常见的用于分发服务器负载或存储空间的方法称为“碎片化”。使用这种方法时,前端服务器将使用 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 如何操作。
我们希望动态生成内容,但在生成后静态存储它。此规则将检查静态文件是否存在,如果不存在,则生成它。如果需要,可以定期删除静态文件(例如,通过 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
,该程序生成请求的资源并将其保存到文档目录中,以便下次请求时,可以提供静态副本。
通过这种方式,可以以静态形式提供很少更新的文档。如果需要刷新文档,可以从文档目录中删除它们,然后在下一次请求时重新生成它们。
我们希望使用 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 拼凑出来的任何东西都要灵活和功能强大。
一些拥有数千个用户的网站使用结构化的主目录布局,即 每个主目录都在一个子目录中,该子目录以用户名首字母开头(例如)。因此,/~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"
默认情况下,重定向到 HTML 锚点不起作用,因为 mod_rewrite 会转义 #
字符,将其变成 %23
。这反过来又会破坏重定向。
在 RewriteRule
上使用 [NE]
标志。NE 代表 No Escape(不转义)。
我们希望使用 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
来控制这种效果。当然,您最好直接动态提供内容,并根据一天中的时间对其进行自定义。有时,我们希望在执行重写时维护某种状态。例如,您想记录您已经执行了该重写,以便以后可以检查请求是否通过该重写而来。一种方法是设置环境变量。
使用 [E] 标志设置环境变量。
RewriteEngine on RewriteRule "^/horse/(.*)" "/pony/$1" [E=rewritten:1]
稍后在您的规则集中,您可以使用 RewriteCond 检查此环境变量
RewriteCond "%{ENV:rewritten}" "=1"
请注意,环境变量不会在外部重定向中保留。您可以考虑使用 [CO] 标志设置 cookie。对于每个目录和 htaccess 重写,其中最终替换被处理为内部重定向,来自上一轮重写的环境变量将以“REDIRECT_”为前缀。