作者:叶歆昊,Discuz!论坛首发,即时更新地址:
http://www.discuz.net/thread-1361331-1-1.html
近期看到论坛上很多网友需要写rewrite,除了默认的rewrite规则,有时想要实现自己的一些跳转,这就需要自写rewrite了,本教程为快速
入门教程,目标是阅读本教程30分钟内对rewrite有所了解能自写简单的rewrite规则,本人较了解Linux的Nginx平台,
出于通用性考虑将rewrite写成Apache适用的,如果需要IIS的rewrite请参照自行修改,本人不深入了解IIS只略只其一二。
楼层导读:
1#:rewrite基本概念
2#:ss默认规则解读以及自写rewrite一般流程
3#:常见问题解答
思考:为什么要伪静态?正常情况下,我的域名
www.littz.cn是指向
64.71.167.26这个IP地址的服务器,服务器上配置了
www.littz.cn的域名是对应 /aaa/www这个目录,假设我们输入一个
http://www.littz.cn/viewnews-340.html,
那么服务器会找/aaa/www目录下有没有viewnews-340.html文件的。但是用SS的朋友你们看看服务器对应目录下有没有这个文件?没有
吧,但是为什么这个URL又能访问呢,是因为rewrite伪静态,服务器的WEB软件(我用的是Nginx,Apache、IIS也是属于这种软件)依
据写的rewrite规则在服务器做了内部处理,实际上是请求index.php,并传递参数action-viewnews-itemid-
340.html给index.php了。
跳转有三种,内部跳转、301永久跳转、302临时跳转。
三者区别在于内部跳转的URL不会改变,搜索引擎会收录这个URL,只能用rewrite实现,例如
http://www.littz.cn/viewnews-340.html,在地址栏看到的还是这个,虽然服务器处理的实际上是
http://www.littz.cn/index.php?action-viewnews-itemid-340。
301跳转:URL改变跳转,可以用php的header、html的meta、javascript或者rewrite规则实现。例如访问
http://www.littz.cn/html/2009/340.html,会跳转到
http://www.littz.cn/viewnews-340.html这个地址。因为搜索引擎原来收录的URL是前者,我不想丢掉任何链接。同时写了301跳转之后,搜索引擎过一段时间会将收录的页面更新到新的URL上。
302跳转和301差不多,不过据说百度不认识而Google认识,当然我没证实过。
灵感:有网友提问,那我能不能写个rewrite实现让
http://www.discuz.net跳转到
http://www.littz.cn呢,这样我的博客不就访问量非常大了?哈哈,可以实现,不过不是用rewrite,用
域名劫持吧
rewrite部分,快速入门就不讲RewriteEngine和RewriteCond了,只说RewriteRule。
RewriteRule顾名思义,伪静态规则。格式为:
- RewriteRule 正则表达式 目标 [类型]
复制代码
RewriteRule做的操作,可以理解为,判断request请求是否符合 第一段的“
正则表达式”,如果符合规则 转给 “
目标” 处理,那是内部跳转还是301跳转呢,由“
类型”决定。
什么是正则表达式?正则表达式 可以理解为很高级的字符串匹配判断语句。例如我们写程序的时候,if ($a ==
abcdef) {;},那么仅仅只能判断$a是否等于“abcdef”。如果我想$a匹配“ab{任意一个字符}def”这个字符串
就可以呢,有些网友会想到windows用的通配符,?代表一个任意字符,*代表任意个任意字符。正则表达式比这个简单的相等判断、通配符判断更多复杂条
件,基本能使用所有的场合。
常见正则表达式的字符串匹配条件:
^ 当且仅当字符开始
$ 当且仅当字符结束
. 任意单个字符
* 0或更多个
+ 1或更多个
? 0或1个
{n,m} n到m个
() 分组
| 或
[a-z] a~z集合内任意一个字符
[] 集合内任意一个字符
[^] 不在集内的任意一个字符
\ 转义专用
正则表达式中为避免判断歧义,必要时应使用()分组以及\转义。
正则表达式只会匹配DOCUMENT_URI部分,不会看主机头和GET传递的参数。
目标:目标为普通字符串,不是正则表达式,有必要时,可以使用$1、$2这些第一段正则表达式匹配出来的变量。
类型:[L]表示如果成功匹配这条RewriteRule,则退出rewrite不会继续判断下一条RewriteRule,[NC]匹配忽略大小写。默认为内部跳转,如果写[R=301] 则为301跳转。
常见规则解读:
- RewriteRule (.*) /test.html [L,R=301]
- #请求的任意URI 301跳转到/test.html
- RewriteRule ^(.*)$ /test.html [L,R=301]
- #这句其实效果和前一个一样,只是判断条件为当且仅当任意字符开始任意字符结束。
- RewriteRule ^(.*) http://www.discuz.net/$1 [R=301,L]
- #把当前主机收到的所有请求全部跳转到http://www.discuz.net/主机,$1这个变量为前面匹配的任意多个字符。适用于整体更换域名,本规则写在原域名下。
- RewriteRule ^/abc/(.*) /def/$1 [R=301,L]
- #匹配以/abc/开始的请求,跳转到/def/,$1为之前匹配的任意多个字符。301跳转。
- #例如请求http://www.littz.cn/abc/jjjjjwerwerew.html,会301跳转到http://www.littz.cn/def/jjjjjwerwerew.html,相当于给def目录建立了一个别名abc。
- RewriteRule ^/type-([0-9]+).html$ /type.php?typeid=$1 [L]
- #匹配以/type-开始的,并且后面接了1个或者多个数字,再后面接上.html的请求,并且以其结束的。内部跳转至/type.php?type=$1处理,$1为[0-9]+匹配得到的数字。
复制代码
官方的SS for Apache Rewrite规则解读
- <IfModule mod_Rewrite.c>
- #如果Apache安装并启用了mod_Rewrite.c模块
- RewriteEngine On
- #启用Rewrite
- ###Rewrite 系统规则请勿修改
- RewriteRule ^/([0-9]+)/spacelist(.+)$ /index.php?uid/$1/action/spacelist/type$2 [L]
- # 开始/{1个或多个数字}/spacelist{1个或多个任意字符}结束,内部跳转到 /index.php?uid/{匹配的数字}/action/spacelist/type{匹配的1个或多个任意字符} 处理
- RewriteRule ^/([0-9]+)/viewspace(.+)$ /index.php?uid/$1/action/viewspace/itemid$2 [L]
- # 开始/{1个或多个数字}/viewspace{1个或多个任意字符}结束,内部跳转到 /index.php?uid/{匹配的数字}/action/viewspace/itemid{匹配的1个或多个任意字符} 处理
- RewriteRule ^/([0-9]+)/viewbbs(.+)$ /index.php?uid/$1/action/viewbbs/tid$2 [L]
- # 开始/{1个或多个数字}/viewbbs{1个或多个任意字符}结束,内部跳转到 /index.php?uid/{匹配的数字}/action/viewbbs/tid{匹配的1个或多个任意字符} 处理
- RewriteRule ^/([0-9]+)/(.*)$ /index.php?uid/$1/$2 [L]
- # 开始/{1个或多个数字}/{任意个任意字符}结束,内部跳转到 /index.php?uid/{匹配的数字}/{匹配的任意个任意字符} 处理
- RewriteRule ^/([0-9]+)$ /index.php?uid/$1 [L]
- # 开始/{1个或多个数字}结束,内部跳转到 /index.php?uid/{匹配的数字}处理
- RewriteRule ^/action(.+)$ /index.php?action$1 [L]
- # 开始/action{任意个任意字符}结束,内部跳转到 /index.php?action/{匹配的任意个任意字符}处理
- RewriteRule ^/category(.+)$ /index.php?action/category/catid$1 [L]
- # 开始/category{任意个任意字符}结束,内部跳转到 /index.php?action/category/catid{匹配的任意个任意字符}处理
- #例如http://www.littz.cn/category-1.html,实际是发给了http://www.littz.cn/index.php?action/category/catid-1.html
- RewriteRule ^/viewnews(.+)$ /index.php?action/viewnews/itemid$1 [L]
- # 开始/viewnews{任意个任意字符}结束,内部跳转到 /index.php?action/viewnews/itemid{匹配的任意个任意字符}处理
- #例如http://www.littz.cn/viewnews-340.html,实际是发给了http://www.littz.cn/index.php?action/viewnews/itemid-340.html
- RewriteRule ^/viewthread(.+)$ /index.php?action/viewthread/tid$1 [L]
- # 开始/viewthread{任意个任意字符}结束,内部跳转到 /index.php?action/viewthread/tid{匹配的任意个任意字符}处理
- RewriteRule ^/mygroup(.+)$ /index.php?action/mygroup/gid$1 [L]
- # 开始/mygroup{任意个任意字符}结束,内部跳转到 /index.php?action/mygroup/gid{匹配的任意个任意字符}处理
- </IfModule>
复制代码
至此,对rewrite应该有一定了解。可以开始自写rewrite了。
下面说的是用rewrite的方法实现,当然可以用其他方法实现,多一种方法。
@@1 原来我用
www.abc.com的网址进我的网站,现在有新的网址
www.littz.cn,但是不想丢掉原URL的链接,又希望所有通过原URL访问的自动跳转到新URL,怎么办呢?
首先保证www.abc还是受你控制的,在
www.abc.com的服务器下写rewrite规则
- RewriteRule ^(.*) http://www.littz.cn/$1 [R=301,L]
复制代码
@@2 原来我的ss放在
http://www.littz.cn/ss,现移动到上级目录了,
http://www.littz.cn,新URL已经能访问,也不想丢掉原URL的链接,又希望所有通过原URL访问的自动跳转到新URL,怎么办呢?
在
www.littz.cn的对应的目录下写rewrite规则。(使用于ss路径已经不会再使用的)
- RewriteRule ^/ss/(.*) http://www.littz.cn/$1 [R=301,L]
复制代码
@@3 原来我的ss放在
http://www.littz.cn/,现移动到supesite目录了,
http://www.littz.cn/supesite,新URL已经能访问,也不想丢掉原URL的链接,又希望所有通过原URL访问的自动跳转到新URL,同时
http://www.littz.cn/的留给我自己写的一些页面用,怎么办呢?
这个时候规则就不能做(.*)的任意判断跳转了。
一、分析哪些URL是需要跳转的,跳转之后到哪里,哪些链接容易出现匹配冲突。
二、确定跳转关系,书写rewrite规则
三、检查rewrite规则,尤其是容易产生匹配冲突的情况。
本例中,要做的判断是仅为SS的URL才跳转至supesite目录中。
- RewriteRule ^/([0-9]+)/spacelist(.+)$ /supesite/$1/spacelist$2 [L,R=301]
- RewriteRule ^/([0-9]+)/viewspace(.+)$ /supesite/$1/viewspace$2 [L,R=301]
- RewriteRule ^/([0-9]+)/viewbbs(.+)$ /supesite/$1/viewbbs$2 [L,R=301]
- RewriteRule ^/([0-9]+)/(.*)$ /supesite/$1/$2 [L,R=301]
- RewriteRule ^/([0-9]+)$ /supesite/$1 [L,R=301]
- RewriteRule ^/action(.+)$ /supesite/action$1 [L,R=301]
- RewriteRule ^/category(.+)$ /supesite/category$1 [L,R=301]
- RewriteRule ^/viewnews(.+)$ /supesite/viewnews$1 [L,R=301]
- RewriteRule ^/viewthread(.+)$ /supesite/viewthread$1 [L,R=301]
- RewriteRule ^/mygroup(.+)$ /supesite/mygroup$1 [L,R=301]
复制代码
常见问题解答:
%%1:根目录有文件,子目录也有文件,如何在根目录配置rewrite规则使其不影响子目录?
假设一个文件结构:
/index.php,/home/index.php。我想通过/home-1.html实际是访问/index.php?homeid-1.html
这个,而通过/home/view-124.html访问/home/index.php?bbsid-124.html这个。
如果简单的写了一条
- RewriteRule ^/home(.+)$ /index.php?homid-$1 [L]
复制代码
这条规则,当然可以把/home-1.html的请求转给/index.php?homid-1.html,但是想想是不是也会把/home/index.php的请求给了/index.php?homeid/index.php ?
这就出现了规则匹配冲突问题,不想要被匹配的URL也跳转了,应该把这个rewrite写的严密些。
- RewriteRule ^/home-([0-9]+)\.html$ /index.php?homid-$1.html [L]
复制代码
这个就只会匹配/home-1.html而不会匹配/home/index.php,所以也就不会产生根目录的rewrite影响子目录。总之就是分析会造成冲突的URL,检查rewrite规则是否有多余的不够严密的