2009年1月19日星期一

Apache Rewrite

在 httpd 中将一个域名转发到另一个域名
虚拟主机世界近期更换了域名,新域名为 www.wbhw.com, 更加简短好记。这时需要将原来的域名 webhosting-world.com, 以及论坛所在地址 webhosting-world.com/forums/ 定向到新的域名,以便用户可以找到,并且使原来的论坛 URL 继续有效而不出现 404 未找到,比如原来的 http://www. webhosting-world.com/forums/-f60.html, 让它在新的域名下继续有效,点击后转发到 http://bbs.wbhw.com/-f60.html, 这就需要用 apache 的 Mod_rewrite 功能来实现。

在<> 中添加下面的重定向规则:

RewriteEngine On
# Redirect webhosting-world.com/forums to bbs.wbhw.com
RewriteCond %{REQUEST_URI} ^/forums/
RewriteRule /forums/(.*) http://bbs.wbhw.com/$1 [R=permanent,L]

# Redirect webhosting-world.com to wbhw.com
RewriteCond %{REQUEST_URI} !^/forums/
RewriteRule /(.*) http://www.wbhw.com/$1 [R=permanent,L]

添加了上面的规则以后, 里的全部内容如下:
<>
ServerAlias webhosting-world.com
ServerAdmin admin@webhosting-world.com
DocumentRoot /path/to/webhosting-world/root
ServerName www.webhosting-world.com

RewriteEngine On
# Redirect webhosting-world.com/forums to bbs.wbhw.com
RewriteCond %{REQUEST_URI} ^/forums/
RewriteRule /forums/(.*) http://bbs.wbhw.com/$1 [R=permanent,L]

# Redirect webhosting-world.com to wbhw.com
RewriteCond %{REQUEST_URI} !^/forums/
RewriteRule /(.*) http://www.wbhw.com/$1 [R=permanent,L]
< /virtualhost>



URL重定向例子一:
1.http://www.zzz.com/xxx.php-> http://www.zzz.com/xxx/
2.http://yyy.zzz.com-> http://www.zzz.com/user.php?username=yyy 的功能

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.zzz.com
RewriteCond %{REQUEST_URI} !^user\.php$
RewriteCond %{REQUEST_URI} \.php$
RewriteRule (.*)\.php$ http://www.zzz.com/$1/ [R]

RewriteCond %{HTTP_HOST} !^www.zzz.com
RewriteRule ^(.+) %{HTTP_HOST} [C]
RewriteRule ^([^\.]+)\.zzz\.com http://www.zzz.com/user.php?username=$1

例子二:
/type.php?typeid=* --> /type*.html
/type.php?typeid=*&page=* --> /type*page*.html

RewriteRule ^/type([0-9]+).html$ /type.php?typeid=$1 [PT]
RewriteRule ^/type([0-9]+)page([0-9]+).html$ /type.php?typeid=$1&page=$2 [PT]

注:
rewritecond 条件重写规则,当满足后面定义的条件后才会应用下面的重写规则,rewritecond有各种变量,请查阅相关文档
-----------------------------------

正则表达式只是用于字符串匹配的特征串, 我们从如何表示一个字符开始.
[ ] : 表示选择一个字符.
(.) : 表示任何了个除换行符(\n)之外的字符.
\r : 表示回车
\n : 表示换行
\t : 表示TAB键
\w : 表示字母,数字或下划线, 等同于[A-Za-z0-9_]
\W : 表示非字母,数字或下划线, 等同于[^A-Za-z0-9_]
\s : 表示空白字符, 等同于[ \f\n\r\t]
\S : 表示非空白字符, 等同于[^ \f\n\r\t]
\d : 表示数字字符, 等同于[0-9]
\D : 表示非数字字符, 等同于[^0-9]
当我们需要表示有特定意义的字符时, 可以用"\"来进行转义, 如要表示一对中括号, 就用"\[\]",其他的类似. 当"*", "+", ".", "(", ")", "$", "?", "", "{"出现在中括号内时, 就只表示字符本身而没有其他含义.
: 或者
* : 表示出现0个或多个
+ : 表示出现1个或多个
? : 表示出现0个或1个
{n} : 表示重复出现n次
{m,n} : 表示重复出现最少m次, 最多n次
到这一部份就比较难理解了, 还是举例子来解释吧.
(abcdef) "ab", "cd", "ef"中的任一个
[a-zA-Z]+ 只包括字母的单词
[A-Z][a-z]* 第一个字母是大写的单词
\d+\.?\d* 表示一个数字
[a-z]{4} 四个小写字母
[+-]?\d*\.\d{1,6} 小数点后有1到6位的数
.\n 任何字符
.* 一行
^\s*$ 空行
-------------总结--------------
其实对于rewrite来说,整体的写法其实很简单
Rewrite 期望地址 源地址写法

而通常而言,改写最多的是对于jsp和asp grenrate出来的那些有数字符的地址转换成静态地址。同时又符合正则表达式。
同时需要注意的是关于[]中的文字表达,
 Flags是可选参数,当有多个标志同时出现时,彼此间以逗号分隔。
'redirect|R [=code]' (强制重定向)
  给当前的URI增加前缀http://thishost[:thisport]/, 从而生成一个新的URL,强制生成一个外部重定向(external redirection,指生的URL发送到客户端,由客户端再次以新的URL发出请求,虽然新URL仍指向当前的服务器). 如果没有指定的code值,则HTTP应答以状态值302 (MOVED TEMPORARILY),如果想使用300-400(不含400)间的其它值可以通过在code的位置以相应的数字指定,也可以用标志名指定: temp (默认值), permanent, seeother.
  注意,当使用这个标志时,要确实substitution是个合法的URL,这个标志只是在URL前增加http://thishost[:thisport]/前缀而已,重写操作会继续进行。如果要立即将新URL重定向,用L标志来中重写流程。
'forbidden|F' (强制禁止访问URL所指的资源)
  立即返回状态值403 (FORBIDDEN)的应答包。将这个标志与合适的RewriteConds 联合使用,可以阻断访问某些URL。
'gone|G' (强制返回URL所指资源为不存在(gone))
  立即返回状态值410 (GONE)的应答包。用这个标志来标记URL所指的资源永久消失了.
# 'proxy|P' (强制将当前URL送往代理模块(proxy module))
  这个标志,强制将substitution当作一个发向代理模块的请求,并立即将共送往代理模块。因此,必须确保substitution串是一个合法的URI (如, 典型的情况是以http://hostname开头),否则会从代理模块得到一个错误. 这个标志,是ProxyPass指令的一个更强劲的实现,将远程请求(remote stuff)映射到本地服务器的名字空间(namespace)中来。
  注意,使用这个功能必须确保代理模块已经编译到Apache 服务器程序中了. 可以用“httpd -l ”命令,来检查输出中是否含有mod_proxy.c来确认一下。如果没有,而又需要使用这个功能,则需要重新编译``httpd''程序并使用mod_proxy有效。
'last|L' (最后一条规则)
  中止重写流程,不再对当前URL施加更多的重写规则。这相当于perl的last命令或C的break命令。
'next|N' (下一轮)
  重新从第一条重写规则开始执行重写过程,新开的过程中的URL不应当与最初的URL相同。 这相当于Perl的next命令或C的continue命令. 千万小心不要产生死循环。
# 'chain|C' (将当前的规则与其后续规则綑绑(chained))
  当规则匹配时,处理过程与没有綑绑一样;如果规则不匹配,则綑绑在一起的后续规则也不在检查和执行。
'type|T=MIME-type' (强制MIME类型)
  强制将目标文件的MIME-type为某MIME类型。例如,这可用来模仿mod_alias模块对某目录的ScriptAlias指定,通过强制将该目录下的所有文件的类型改为 “application/x-httpd-cgi”.
'nosubreq|NS' (used only if no internal sub-request )
  这个标志强制重写引擎跳过为内部sub-request的重写规则.例如,当mod_include试图找到某一目录下的默认文件时 (index.xxx),sub-requests 会在Apache内部发生. Sub-requests并非总是有用的,在某些情况下如果整个规则集施加到它上面,会产生错误。利用这个标志可排除执行一些规则。
'nocase|NC' (模板不区分大小写)
  这个标志会使得模板匹配当前URL时忽略大小写的差别。
'qsappend|QSA' (追加请求串(query string))
  这个标志,强制重写引擎为Substitution的请求串追加一部分串,则不是替换掉原来的。借助这个标志,可以使用一个重写规则给请求串增加更多的数据。
'noescape|NE' (不对输出结果中的特殊字符进行转义处理)
  通常情况下,mod_write的输出结果中,特殊字符(如'%', '$', ';', 等)会转义为它们的16进制形式(如分别为'%25', '%24', and '%3B')。这个标志会禁止mod_rewrite对输出结果进行此类操作。 这个标志只能在 Apache 1.3.20及以后的版本中使用。
'passthrough|PT' (通过下一个处理器)
  这个标志强制重写引擎用filename字段的值来替换内部request_rec数据结构中uri字段的值。. 使用这个标志,可以使后续的其它URI-to-filename转换器的Alias、ScriptAlias、Redirect等指令,也能正常处理RewriteRule指令的输出结果。用一个小例子来说明它的语义:如果要用mod_rewrite的重写引擎将/abc转换为/def,然后用mod_alas将/def重写为ghi,则要:
RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghi
如果PT标志被忽略,则mod_rewrite也能很好完成工作,如果., 将 uri=/abc/... 转换为filename=/def/... ,完全符合一个URI-to-filename转换器的动作。接下来 mod_alias 试图做 URI-to-filename 转换时就会出问题。
注意:如果要混合都含有URL-to-filename转换器的不同的模块的指令,必须用这个标志。最典型的例子是mod_alias和mod_rewrite的使用。
'skip|S=num' (跳过后面的num个规则)
  当前规则匹配时,强制重写引擎跳过后续的num个规则。用这个可以来模仿if-then-else结构:then子句的最后一条rule的标志是skip=N,而N是else子句的规则条数。
'env|E=VAR:VAL' (设置环境变量)
  设置名为VAR的环境变量的值为VAL,其中VAL中可以含有正则式的后向引用($N或%N)。这个标志可以使用多次,以设置多个环境变量。这儿设置的变量,可以在多种情况下被引用,如在XSSI或CGI中。另外,也可以在RewriteCond模板中以%{ENV:VAR}的形式被引用。

RewriteRule news/(\d+)\.html news\.php\?id=$1 [N,L]
这样就实现了将http://localhost/news/1000.html 解析为 http://localhost/news.php?id=1000的功能
http://211.100.227.106:8080/wp-cp-m7/index.jsp?mod=free&act=watch&cid=714
index/[a-zA-Z]/[a-zA-Z]/(\d+)_(\d+)\.html index\.jsp\?mod=$1&act=$2&cid=
RewriteRule ^(power([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
$ 匹配输入字符串的结束位置。如
将URL http://host/test.jps?id=1 重定向为 http://host/1.html
将URL http://host/conent.jsp?id=1&id2=3 重定向为 http://host/1_3.html
RewriteEngine on
RewriteRule /([0-9]+).html /test.jsp?id=$1 [PT]
RewriteRule /([0-9]+)_([0-9]+).html /content.jsp?id=$1&id2=$2 [PT]
index.jsp?lid=2&mod=free&act=watch&cid=714&mid=112312&type=adlska
index/lang/mod/act/type/cid_mid.html
RewriteRule index/(\d+\.?\d*)/(a-z)/(a-z)/(a-z)/([0-9]+)_([0-9]+).html /index.jsp?lid=$1&mod=&2&act=$3&type=$4&cid=$5&mid=$6 [PT]
RewriteRule index/(a-z)/(a-z)/(a-z)/([0-9]+)_([0-9]+).html /index.jsp?mod=&1&act=$2&type=$3&cid=$4&mid=$5 [PT]
RewriteRule /(a-z)/(a-z)/([0-9]+)_([0-9]+).html /?mod=&1&act=$2&cid=$3&mid=$4 [PT]
index.jsp?mod=free&act=watch&cid=714
index.jsp?mod=free&act=watch
index.jsp?mod=free

RewriteRule ^([^/]+)/([^/]+)/(\d+)_(\d+).html$ /index.jsp?mod=$1&act=$2&cid=$3&mid=$4
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/(\d+)_(\d+).html$ /index.jsp?lid=$1&mod=$2&act=$3&cid=$4&mid=$5

RewriteRule ^([^/]+)/([^/]+)/(\d+).html$ /index.jsp?mod=$1&act=$2&cid=$3
RewriteRule ^([^/]+)/([^/]+)/(\d+)/(\d+).html$ /index.jsp?lid=$1&mod=$2&act=$3&cid=$4

RewriteRule ^(\d+)/(\d+).html$ /index.jsp?mod=$1&act=$2
RewriteRule ^(\d+)/([^/]+)/([^/]+).html$ /index.jsp?lid=$1&mod=$2&act=$3

RewriteRule ^([^/]+).html$ /index.jsp?mod=$1
RewriteRule ^(\d+)/([^/]).html$ /index.jsp?lid=$1&mod=$2

没有评论: