/ 中存储网

Nginx的Rewrite伪静态规则配置解析

2013-12-14 16:30:01 来源:itjs.cn

Nginx以其良好的并发性能,目前正在逐渐取代Apache成为大家的Web server首选,但是Nginx目前的中文资料很少,需要大家努力贡献。

下面我介绍一下Nginx的Rewrite模块设置及Wordpress和Discuz的示例。Nginx的Rewrite规则比Apache的简单灵活多了,从下面介绍可见一斑。

首先,Nginx可以用if进行条件匹配,语法规则类似C,举例如下:

if ($http_user_agent ~ MSIE) {

rewrite ^(.*)$ /msie/$1 break;

}

1、正则表达式匹配

* ~ 为区分大小写匹配

* ~* 为不区分大小写匹配

* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配

2、文件及目录匹配

* -f和!-f用来判断是否存在文件

* -d和!-d用来判断是否存在目录

* -e和!-e用来判断是否存在文件或目录

* -x和!-x用来判断文件是否可执行

如:

if (!-f $request_filename) {

proxy_pass http://127.0.0.1;

}

另外,当用户输入网址最后是目录时,可以用以下rewrite规则自动加“/”

if (-d $request_filename){

rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;

}

这句rewrite是我特意写的,用来解决以下问题:如果类似http://www.abc.com/home/index.html的网址,用户输入http://www.abc.com/home来访问,Nginx是无法自动定位到index.html文件的,会显示一个该文件无法找到的报错页。if (-d $request_filename)这句表示的是如果请求的URL是一个目录(即URL中的home是一个目录),则执行里面的语句:rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;表示将 http://www.abc.com/home 这串URL rewrite成 http://www.abc.com/home/。通过 http://www.abc.com/home/ 就能够访问到该目录下的index文件了。

需要注意的是:nginx的rewrite的后半部分URL实际地址那里应该是不支持正则的, 也就是说转义符是没必要的, 不然就会造成从””开始就断了URL重写。如:

 rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/viewthread.php?tid=$2&extra=page%3D$4&page=$3 last;

其实这条规则的不对的,正确的写法应该是:

 rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/viewthread.php?tid=$2&extra=page%3D$4&page=$3 last;

其次,Nginx的Rewrite规则与Apache几乎完全一致,所不同的是最后的flag标记,举例如下:

 rewrite ^/feed/$ http://feed.shunz.net last;

flag标记

* last 相当于Apache里的[L]标记,表示完成rewrite,不再匹配后面的规则

* break 与last类似

* redirect 返回302临时重定向

* permanent 返回301永久重定向

nginx rewrite中last和break的区别

在实际配置中,有的地方用last并不能工作,换成break就可以,其中的原理是对于根目录的理解有所区别,按我的测试结果大致是这样的。

location / {

proxy_pass http://test;

alias /home/html/;

root /home/html;

rewrite “^/a/(.*).html$” /1.html last;

}

在#location / { 配置里:

使用root指定源:使用last和break都可以

使用proxy_pass指定源:使用last和break都可以

使用alias指定源:必须使用last

在location /a/或使用正则的location ~ ^/a/里:

使用root指定源:使用last和break都可以

使用proxy_pass指定源:使用break和last结果有所区别

使用alias指定源:必须使用last

其中区别主要在proxy_pass这个标签上,再看看几个测试结果:

location / {

root /home/html;

}

location /a/ {

proxy_pass http://test;

rewrite “^/a/(.*).html$” /1.html last;

}

在这段配置里,使用last访问是可以访问到东西的,不过,它出来的结果是:/home/html/1.html;可我需要的是http://test/1.html?使用break就可以了。

location / {

root /home/html;

}

location /a/ {

proxy_pass http://test;

rewrite “^/a/(.*).html$” /a/1.html last;

}

在这段配置里,返回错误,因为last会重新发起请求匹配,所以造成了一个死循环,使用break就可以访问到http://test/a/1.html。所以,使用last会对server标签重新发起请求,而break就直接使用当前的location中的数据源来访问,要视情况加以使用。一般在非根的location中配置rewrite,都是用的break;而根的location使用last比较好,因为如果配置了fastcgi或代理访问jsp文件的话,在根location下用break是访问不到。测试到rewrite有问题的时候,也不妨把这两者换换试试。至于使用alias时为什么必须用last,估计是nginx本身就限定了的,怎么尝试break都不能成功。

nginx对大括号的支持

在nginx中这样写规则

 rewrite ^/([0-9]{5}).html$ /x.jsp?id=$1 last;

是无法启动的,解决的办法是加上两个双引号

 rewrite “^/([0-9]{5}).html$” /x.jsp?id=$1 last;

这样就OK了,应该可以说是完全兼容apache的语法的,只需要改下RewriteRule为Rewrite,后面的一般可以这样对应改一些可用的全局变量有,可以用做条件判断(待补全)

$args

$content_length

$content_type

$document_root

$document_uri

$host

$http_user_agent

$http_cookie

$limit_rate

$request_body_file

$request_method

$remote_addr

$remote_port

$remote_user

$request_filename

$request_uri

$query_string

$scheme

$server_protocol

$server_addr

$server_name

$server_port

$uri

举例:abc.domian.com/sort/2 => abc.domian.com/index.php?act=sort&name=abc&id=2

if ($host ~* (.*).domain.com) {

set $sub_name $1;

rewrite ^/sort/(d+)/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;

}

WordPress的重定向规则:

if (!-e $request_filename) {

rewrite ^/(index|atom|rsd).xml$ http://feed.shunz.net last;

rewrite ^([_0-9a-zA-Z-]+)?(/wp-.*) $2 last;

rewrite ^([_0-9a-zA-Z-]+)?(/.*.php)$ $2 last;

rewrite ^ /index.php last;

}

Discuz!的重定向规则:

if (!-f $request_filename) {

rewrite ^/archiver/((fid|tid)-[w-]+.html)$ /archiver/index.php?$1 last;

rewrite ^/forum-([0-9]+)-([0-9]+).html$ /forumdisplay.php?fid=$1&page=$2 last;

rewrite ^/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ /viewthread.php?tid=$1&extra=page%3D$3&page=$2 last;

rewrite ^/space-(username|uid)-(.+).html$ /space.php?$1=$2 last;

rewrite ^/tag-(.+).html$ /tag.php?name=$1 last;

}