当前位置: > Linux服务器 > nginx >

Nginx URL Rewrite – URL 转发规则

时间:2016-05-27 19:10来源:linux.it.net.cn 作者:IT

Nginx(engine x)是由Igor Sysoev主导设计和实现的高性能的web服务器和邮件代理服务器,目前它已经成为代替在web服务器市场遥遥领先的apache服务器的首选替代品. 随着越来越多的大型站点的加入(大房注:国内有新浪、网易、六间房、豆瓣等,国外有wordpress等)Nginx的市场份额在稳步和飞快的提升。 在这片文章里,我们会主要关注一下Nginx的配置以及虚拟目录的配置方面的内容。 说明:通过虚拟目录,你可以使用一个独立IP建立多个web站点,每个web站点拥有自己独立的.htaccess(假设你已经很熟悉Aapache)文件和独立的目录等。 例如,你可以拥有一个使用wordpress搭建的博客站点,同时你也可以拥有一个MODx系统,或者phpBB。使用Nginx,你将不再能享受.htaccess文件带来的好处,所有这些位于.htaccess文件里的配置都需要转移至Nginx的配置文件去。 Nginx在URL转发上面还是有一些限制,例如你不可以像使用apache的rewrite规则一样对同一个URL应用多条条件转发规则。 但是,Nginx支持if语句 ,这样,你可以将一些转发规则写到if语句里。同样,Nginx的if语句自身也有一定的限制,例如,它不支持“and”和“or”操作,也不可以if语句里嵌套if语句,也没有else语句。但是,你却可以使用正则表达式:

[PHP]
if ($request_method !~ ^(GET|HEAD)$ ) {#如果请求的方法不是GET或者HEAD,则返回501错误
return 501;
}
[/php]

注意,你不可以在if语句里同时判断两个参数(例如:if ($request_method !~ ^(GET)$ || $request_method !~ ^(HEAD)$))但是,稍微思考一下,我们还是有更好的办法弥补这种不足来满足特定的需求 ,举个例子来说,一个非常常见的.htaccess定义的转发规则可能如下:

[php]
RewriteEngine On #开启转发功能
RewriteBase / #转发的基目录
RewriteCond %{REQUEST_FILENAME} !-f #转发条件,如果请求的文件不存在
RewriteCond %{REQUEST_FILENAME} !-d #转发条件,如果请求的目录不存在
RewriteRule . /index.php [L] #转发规则,如果文件或者目录不存在则转发请求到index.php文件
【说明:以上注释由Wyatt添加 】
[/php]

上面定义的转发规则是说,如果请求的文件不存在但它也不是一个存在的目录的话,则转发请求到index.php文件。 以上的转发条件可能对大多数的PHP系统都适用,但是转发规则却不一定,例如,以下的转发规则摘自phpBB系统:

[php]
RewriteCond %{REQUEST_FILENAME} !-f #转发条件,如果请求的文件不存在
RewriteCond %{REQUEST_FILENAME} !-d #转发条件,如果请求的目录不存在
RewriteCond %{REQUEST_FILENAME} !-l #转发规则,如果请求的文件不存在符号链接
RewriteRule ^[a-z0-9_-]+/?(p([0-9]+).html)?$ /viewforum.php?start=$2 [QSA,L,NC]
#转发规则,将请求满足正则表达式的请求转发到viewforum。
[/php]

暂时忽略第三条转发条件,它同时检查了符号链接,你会看到转发条件和前面的例子一样,但是转发规则却不一致。假设你要在你的服务器上(同一IP)同时建立wordpress的站点和phpBB站点,那么你会将相同的转发条件作为公用的配置:

# 如果请求的文件是一个存在的文件或者一个存在的目录或者是存在的符号链接

[php] if (-e $request_filename) {     break; } [/php]

这里的配置和前面的转发条件(RewriteCond)做的是同样的事情,同时这里的配置会应用到所有在该服务器上的站点(假设你将这些站点都放置在同一台服务器上)。 接下来,你可以对不同的站点设置不同的转发推个,例如,针对wordpress站点:

[php]
# 对blog.example.com的转发规则
if ($host ~* ^blog.example.com$) { #如果host包含blog.example.com(不区分大小写),则应用if块里的转发规则
rewrite  ^(.*)$  /index.php?q=$1  last;
break;
}
[/php]

这里的last保证了之应用当前的转发规则,不再做后续的规则匹配和查找。 我还发表了其它几篇文章来讲述虚拟目录的配置,它们是:

  1. 如何使用Ngnix配置虚拟目录运行phpBB;
  2. Nginx: how to fix directory resolution issue as well as internal re-directs in virtual hosting
  3. 如何基于Ngnix配置虚拟目录

让我们更深入一些以结束这一章节的介绍。如何避免以“点”开头的文件(例如.htaccess)被其他用户访问到?增加如下的配置到你的Nginx的配置文件里:

location ~ /. {
    deny  all;
}

这三行的配置将拒绝为任何外部的请求你的服务器上的以“点”开头的文件的请求。 如何转发以WWW开头的URL到不包含WWW的URL上去? 例如,下面的配置将可以使你将请求http://www.example.com/yourpage 转发至 http://example.com/yourpage:

[php]
if ($host ~* ^www.(.*)) {#如果请求的host包含www(不区分大小写),扩号里的为匹配项,下面用$1引用该值    
set $host_without_www $1;    
rewrite ^(.*)$ http://$host_without_www$1 permanent;
# $1 contains ‘/yourpage’, not ‘www.example.net/yourpage’ }
[/php]

说明:这个例子来自于Nginx的官方网站的文档:如何将Apache HTTPD 转发规则转移到Nginx上来?在那边文章里我已经讲到了几个关键点,其中最主要的一点就是,HTTPD的转发规则中是不需要以“/”来开头的,但是Nginx却是需要以“/”来开头 ,举例来说,Apache的转发规则可能像下面的样子:

[php]
RewriteRule ^[a-z0-9_-]*-f([0-9]+)/?(p([0-9]+).html)?$ /viewforum.php?f=$1&start=$3 [QSA,L,NC]
[/php]

而同样的转发规则在Nginx下却变成了这样(注意前面的“/”):

[php]
rewrite ^/[a-z0-9_-]*-f([0-9]+)/?(p([0-9]+).html)?$ /viewforum.php?f=$1&start=$3 last; [/php]

是不是很简单?

注意:Apache里的转发条件却需要使用Nginx里的if语句来实现 。

另一个问题,如何不让Nginx来记录对用户对图片或者静态资源的请求呢?如何来确定静态文件如图片等的客户端缓存过期时间呢?

[php]
# serve static files directly
location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|html)$ {    
access_log        off;    
expires           30d;
}
[/php]

以上只是简单的介绍,欢迎大家提问题到我们的论坛来。

大房注:以上的内容是我翻译的一篇英文Nginx URL 转发的文章。目前Nginx的使用范围越来越广,越来越多的网站系统开始投向Ngnix的怀抱,但是Nginx的中文资料(甚至英文资料都比较缺)比较少。昨天在配置Ngnix的URL转发,顺便晚上把这篇文章翻译过来。如果你喜欢阅读英文文档,可以查看英文原文。

大房补充nginx rewrite的一些参数::

1. 正则表达式匹配,其中:
~  为区分大小写匹配
~* 为不区分大小写匹配
!~和!~*分别为区分大小写不匹配及不区分大小写不匹配

注意:Nginx里面配置 {m,n} 这样的正则规则的时候,条件必须加上双引号
2. 文件及目录匹配,其中:
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行
3. flag标记有:
last 相当于Apache里的[L]标记,表示完成rewrite,不再匹配后面的规则
break 与last类似
redirect 返回302临时重定向
permanent 返回301永久重定向



4. 一些可用的全局变量有,可以用做条件判断(部分)

$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




(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容