Apache初级URL重写指南

2007-12-04 22:56

Apache模块 mod_rewrite


说明一个基于一定规则的实时重写URL请求的引擎
状态扩展(E)
模块名rewrite_module
源文件mod_rewrite.c
兼容性仅在 Apache 1.3 及以后的版本中可用

概述

此模块提供了一个基于正则表达式分析器的重写引擎来实时重写URL请求。它支持每个完整规则可以拥有不限数量的子规则以及附加条件规则的灵活而且强大的URL操作机制。此URL操作可以依赖于各种测试,比如服务器变量、环境变量、HTTP头、时间标记,甚至各种格式的用于匹配URL组成部分的查找数据库。

此模块可以操作URL的所有部分(包括路径信息部分),在服务器级的(
httpd.conf
)和目录级的(
.htaccess
)配置都有效,还可以生成最终请求字符串。此重写操作的结果可以是内部子处理,也可以是外部请求的转向,甚至还可以是内部代理处理。

但是,所有这些功能和灵活性带来一个问题,那就是复杂性,因此,不要指望一天之内就能看懂整个模块。


注意:根据你的服务器配置,有可能必须对这里的例子作些小修改,比如,在额外启用
mod_alias

mod_userdir
的情况下要增加
[PT]
标志,或者为了适应目录级(
.htaccess
)的配置而将针对服务器级的规则集进行重写。对一个特定的规则集应该先透彻理解然后再考虑应用,这样才能避免出现问题。
top
规范化URL
描述:
在有些web服务器上,一个资源会拥有多个URL。在实际应用和发布中应该使用的是规范的URL,其他的则是简写或者只在内部使用。无论用户在请求中使用什么形式的URL,最终看见的都应该是规范的URL。
解决方案:
对所有不规范的URL执行一个外部HTTP重定向,以改变它在浏览器地址栏中的显示及其后继请求。下例中的规则集用规范的
/u/user
替换
/~user
,并修正了
/u/user
所遗漏的后缀斜杠。
RewriteRule   ^/~([^/]+)/?(.*)    /u/$1/$2  [R]  RewriteRule   ^/([uge])/([^/]+)$  /$1/$2/   [R]


top
规范化主机名
描述:
这个规则的目的是强制使用特定的主机名以代替其他名字。比如,你想强制使用www.example.com代替example.com,就可以在以下方案的基础上进行修改:
解决方案:

对运行在非80端口的站点


RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]  RewriteCond %{HTTP_HOST}   !^$  RewriteCond %{SERVER_PORT} !^80$  RewriteRule ^/(.*)         http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]

对运行在80端口的站点


RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]  RewriteCond %{HTTP_HOST}   !^$  RewriteRule ^/(.*)         http://fully.qualified.domain.name/$1 [L,R]


top
移动过的
DocumentRoot

描述:
通常,web服务器的
DocumentRoot
直接对应于URL"
/
",但是它常常不是处于最高的一级。比如,你希望访问者在进入网站时首先进入
/about/
目录。可以使用下面给出的规则集。
解决方案:
只需将"
/
"重定向到"
/about/
"即可:
RewriteEngine on  RewriteRule   ^/$  /about/  [R]

也可以使用
RedirectMatch
指令解决问题:



RedirectMatch ^/$ http://example.com/e/www/



top
结尾斜杠问题
描述:
每个网管对引用目录的结尾斜杠问题都有一本苦经,如果遗漏了,服务器会产生一个错误,因为如果请求是"/~quux/foo"而不是"/~quux/foo/",服务器就会去找一个叫foo的文件,而它是一个目录,所以就报错了。通常,可以使用这个 FAQ entry里面提到的方法解决问题。但是有时候需要使用重写规则来解决问题,比如,在应用了许多复杂的重写规则之后。
解决方案:
解决这个微妙问题的方案是让服务器自动添加后缀斜杠。为了达到目的,必须使用一个外部重定向,以使浏览器能够正确地处理后继的请求(比如对图片的请求)。如果仅仅执行一个内部重写,可能仅仅对目录页面有效,而对含有相对URL的图片的页面无效,因为浏览器有请求内嵌目标的可能。比如,如果不用外部重定向,对
/~quux/foo/index.html
页面中的
image.gif
的请求将变成对
/~quux/image.gif
的请求!所以,应该这样写:
RewriteEngine  on  RewriteBase    /~quux/  RewriteRule    ^foo$  foo/  [R]

又懒又疯狂的做法是把这些写入其宿主目录中的顶级
.htaccess
中:


RewriteEngine  on  RewriteBase    /~quux/  RewriteCond    %{REQUEST_FILENAME}  -d  RewriteRule    ^(.+[^/])$           $1/  [R]

但是这样一来会增加处理上的开销。


top
将用户主目录移动到不同web服务器
描述:
通常,许多网管在建立一个新的web服务器时,都会有这样的要求:重定向一个web服务器上的所有用户主目录到另一个web服务器。
解决方案:
很简单,在老的web服务器上重定向所有的"
/~user/anypath
"到"
http://newserver/~user/anypath
":
RewriteEngine on  RewriteRule   ^/~(.+)  http://newserver/~$1  [R,L]


top
在多个目录中搜索页面
描述:
有时会有必要使web服务器在多个目录中搜索页面,对此,MultiViews或者其他技术无能为力。
解决方案:
编制一个明确的规则集以搜索目录中的文件:
RewriteEngine on    # 首先尝试在 dir1 中寻找,找到即停  RewriteCond         /your/docroot/dir1/%{REQUEST_FILENAME}  -f  RewriteRule  ^(.+)  /your/docroot/dir1/$1  [L]    # 然后尝试在 dir2 中寻找,找到即停  RewriteCond         /your/docroot/dir2/%{REQUEST_FILENAME}  -f  RewriteRule  ^(.+)  /your/docroot/dir2/$1  [L]    # 再找不到就继续寻找其他的 Alias 或 ScriptAlias 目录  RewriteRule   ^(.+)  -  [PT]


top
按照URL的片段设置环境变量
描述:
希望保持请求之间的状态信息,又不希望使用CGI来包装所有页面,只是通过分离URL中的有用信息来做到。
解决方案:
可以用一个规则集来分离出状态信息,并设置环境变量以备此后用于XSSI或CGI。这样,一个"
/foo/S=java/bar/
"的URL会被解析为"
/foo/bar/
",而环境变量
STATUS
则被设置为"java"。
RewriteEngine on  RewriteRule   ^(.*)/S=([^/]+)/(.*)    $1/$3 [E=STATUS:$2]


top
虚拟用户主机
描述:
如果需要为用户username支持一个
www.username.host.domain.com
的主页,但不在此机器上建虚拟主机,而是仅用在此机器上增加一个DNS A记录的方法实现。
解决方案:
仅能对包含"Host: "头的HTTP/1.1请求实现。可以使用以下规则集内部地将
http://www.username.host.com/anypath
重写为
/home/username/anypath
RewriteEngine on  RewriteCond   %{HTTP_HOST}                 ^www\.[^.]+\.host\.com$  RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]  RewriteRule   ^www\.([^.]+)\.host\.com(.*) /home/$1$2


top
为外来访问者重定向用户主目录
描述:
对不是来自本地域
ourdomain.com
的外来访问者的请求,重定向其用户主目录URL到另一个web服务器
www.somewhere.com
,有时这种做法也会用在虚拟主机的配置段中。
解决方案:
只须一个重写条件:
RewriteEngine on  RewriteCond   %{REMOTE_HOST}  !^.+\.ourdomain\.com$  RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]


top
重定向锚
描述:
默认情况下,重定向到一个HTML锚是不可行的,因为'
#
'会被转义为'
%23
'。This, in turn, breaks the redirection.
解决方案:

RewriteRule
指令中使用
[NE]
标志(不转义)。

top
依赖于时间的重写
描述:
在页面内容需要按时间的不同而变化的场合,比如重定向特定页面等,许多网管仍然采用CGI脚本的方法,如何用
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  RewriteRule   ^foo\.html$             foo.night.html

此例使
foo.html

07:00-19:00
时间内指向
foo.day.html
,而在其余时间指向
foo.night.html
,对主页是一个不错的功能...


top
对YYYY转变为XXXX的向前兼容
描述:
在转变了大批
document.YYYY
文件为
document.XXXX
后(比如
.html

.phtml
),如何保持URL的向前兼容(仍然虚拟地存在)?
解决方案:
只须按基准文件名重写,并测试带有新的扩展名的文件是否存在,如果存在则用新的,否则仍然用原来的。


# 将document.html重写为document.phtml的向后兼容的规则集  # 当且仅当document.phtml存在且document.html不存在的时候  RewriteEngine on  RewriteBase   /~quux/  # 剪切并记住basename  RewriteRule   ^(.*)\.html$              $1      [C,E=WasHTML:yes]  # 如果存在的话就重写为document.phtml  RewriteCond   %{REQUEST_FILENAME}.phtml -f  RewriteRule   ^(.*)$ $1.phtml                   [S=1]  # 否则返回先前的basename  RewriteCond   %{ENV:WasHTML}            ^yes$  RewriteRule   ^(.*)$ $1.html


top
内容处理
从旧到新(内部)
描述:
假定已经把文件
foo.html
改名为
bar.html
,需要对老的URL向后兼容,即让用户仍然可以使用老的URL,而感觉不到文件被改名了。
解决方案:
通过以下规则内部地将老的URL重写为新的:
RewriteEngine  on  RewriteBase    /~quux/  RewriteRule    ^foo\.html$  bar.html


从旧到新(外部)
描述:
仍然假定已经把文件
foo.html
改名为
bar.html
,需要对老的URL向后兼容,但是要让用户得到文件被改名的暗示,即浏览器的地址栏中显示的是新的URL。
解决方案:
作一个HTTP的强制重定向以改变浏览器和用户界面上的显示:
RewriteEngine  on  RewriteBase    /~quux/  RewriteRule    ^foo\.html$  bar.html  [R]


从静态到动态
描述:
如何无缝转换静态页面
foo.html
为动态的
foo.cgi
,而不为浏览器/用户所察觉。
解决方案:
只须重写此URL为CGI-script,并强制作为CGI-script运行的MIME类型。比如对
/~quux/foo.html
的请求会执行
/~quux/foo.cgi

RewriteEngine  on  RewriteBase    /~quux/  RewriteRule    ^foo\.html$  foo.cgi  [T=application/x-httpd-cgi]


top
访问控制
阻止Robot
描述:
如何阻止一个完全匿名的Robot取得特定网络区域的页面?
/robots.txt
文件可以包含若干"Robot排除协议"行,但不足以阻止此类Robot。
解决方案:
可以用一个规则集以拒绝对网络区域
/~quux/foo/arc/
(对一个很深的目录区域进行列表可能会使服务器产生很大的负载)的访问。还必须确保仅阻止特定的Robot,也就是说,仅仅阻止Robot访问主机是不够的(这样会同时阻止用户访问该主机)。为此,就需要对HTTP头的User-Agent信息作匹配。
RewriteCond %{HTTP_USER_AGENT}   ^NameOfBadRobot.*  RewriteCond %{REMOTE_ADDR}       ^123\.45\.67\.[8-9]$  RewriteRule ^/~quux/foo/arc/.+   -   [F]


阻止内嵌的图片
描述:
假设
http://www.quux-corp.de/~quux/
有一些内嵌GIF图片的页面,这些图片很好,所以就有人盗链到他们自己的页面中了。由于这样徒然增加了我们服务器的流量,因此,我们不愿意这种事情发生。
解决方案:
虽然,我们不能100%地保护这些图片不被写入别人的页面,但至少可以对发出HTTP Referer头的浏览器加以限制。
RewriteCond %{HTTP_REFERER} !^$  RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]  RewriteRule .*\.gif$        -                                    [F]

RewriteCond %{HTTP_REFERER}         !^$  RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$  RewriteRule ^inlined-in-foo\.gif$   -                        [F]


拒绝代理
描述:
如何拒绝某个主机或者来自特定主机的用户使用Apache代理?
解决方案:
首先,要确保在配置文件中
mod_rewrite
位于
mod_proxy
之后!使它在
mod_proxy
之前被调用。然后,使用如下方法拒绝某个主机:
RewriteCond %{REMOTE_HOST} ^badhost\.mydomain\.com$  RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]

使用如下方法拒绝user@host-dependent用户:


RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST}  ^badguy@badhost\.mydomain\.com$  RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]


top
其它
外部重写引擎
描述:
如何解决似乎无法用
mod_rewrite
解决的FOO/BAR/QUUX/之类的问题?
解决方案:
可以使用一个与
RewriteMap
功能相同的外部
RewriteMap
程序,一旦它在Apache启动时被执行,则从
STDIN
接收被请求的URL ,并将处理过(通常是重写过的)的URL(以相同顺序)在
STDOUT
输出。
RewriteEngine on  RewriteMap    quux-map       prg:/path/to/map.quux.pl  RewriteRule   ^/~quux/(.*)$  /~quux/${quux-map:$1}

#!/path/to/perl    # 禁止使用会导致Apache陷入死循环的I/O缓冲  $| = 1;    # 从stdin读取URL(每行一个),并在stdout输出替换URL  while (<>) {      s|^foo/|bar/|;      print $_;  }

这是只是一个简单的示例,只是把所有的
/~quux/foo/...
重写为
/~quux/bar/...
而已。但事实上,可以把它修改成任何你想要的输出。但是要注意,虽然一般用户都可以使用,可是只有系统管理员才可以定义这样的映射。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值