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;
}