Rewrite主要的功能就是实现URL的重写,Nginx的Rewrite规则采用PCRE Perl兼容正则表达式的语法进行规则匹配,如果需要Nginx的Rewrite功能,在编译Nginx之前,需要编译安装PCRE库。

通过Rewrite规则,可以实现规范的URL、根据变量来做URL转向及选择配置。例如,一些使用MVC框架的程序只有一个入口,可以通过Rewrite开实现。一些动态URL地址需要伪装成静态HTML,便于搜索引擎抓取,也需要Rewrite来处理。一些由于目录结构、域名变化的旧URL,需要跳转到新URL上,也可以通过Rewrite来处理。

Rewrite规则相关指令

Rewrite规则相关指令有if、rewrite、set、return、break等,其中rewrite是最关键的指令。一个简单的Nginx Rewrite规则语法如下:

1
rewrite ∧/b/(.*)\.html /play.php?video=$1 break;

如果加上if语句,示例如下:

1
2
3
4
if (!-f $request_filename)
{
rewrite ∧/img/(.*)$ /site/$host/images/$1 last;
}
break指令

语法:break

默认值:none

使用环境:server,location,if

该指令的作用是完成当前的规则集,不再处理rewrite指令。

示例如下:

1
2
3
4
5
if ($slow)
{
limit_rate 10k;
break;
}
if指令

语法:if(condition){…}

默认值:none

使用环境:server,location

该指令用于检查一个条件是否符合,如果条件符合,则执行大括号内的语句。if指令不支持嵌套,不支持多个条件&&和||处理。

以下信息可以被指定为条件:

  1. 变量名,错误的值包括:空字符串“ ”,或者任何以0开始的字符串;
  2. 变量比较可以使用“=”(表示等于)和“!=”(表示不等于)运算符;
  3. 正则表达式模式匹配可以使用“*”和“”符号;
  4. “~”符号表示区分大小写字母的匹配;
  5. “~*”符号表示不区分大小写字母的匹配(例如firefox和FireFox是匹配的);
  6. “!”和“!*”符号的作用刚好和“”、“!”相反,表示不匹配;
  7. “-f”和“!-f”用来判断文件是否存在;
  8. “-d”和“!-d”用来判断目录是否存在;
  9. “-e”和“!-e”用来判断文件或目录是否存在;
  10. “-x”和“!-x”用来判断文件是否可执行。

部分正则表达式可以在圆括号“()”内,其值可以通过后面的变量$1$9访问,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if ($http_user_agent ~ MSIE) {
rewrite ∧(.*)$ /msie/$1 break;
}

if ($http_cookie ~* "id=([∧;] +)(?:;|$)" ) {
set $id $1;
}

if ($request_method = POST) {
return 405;
}

if (!-f $request_filename) {
break;
proxy_pass http://127.0.0.1;
}

if ($slow) {
limit_rate 10k;
}

if ($invalid_referer) {
return 403;
}

if ($arge ∧~ post=140) {
rewrite ∧ http://example.com/permanent;
}

以上示例代码中,内置的变量$invalid_referer值由valid_referers指令提供。

return指令

语法:return code

默认值:none

使用环境:server,location,if

该指令用于结束规则的执行并返回状态码给客户端。状态码可以使用这些值:204,400,402406,408,411,413,416及500504。此外,非标准状态码444将以不发送任何Header头的方式结束连接。

示例,如果访问的URL以“.Sh”和“.Bash”结尾,则返回状态码403:

1
2
3
4
location ~ .*\.(sh|bash)?$
{
return 403;
}

下面,我们来详细介绍return指令支持的状态码。

204 No Content

服务器成功处理了请求,但无需返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。

如果客户端是浏览器,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息,也应当被应用到用户浏览器活动视图中的文档。

400 Bad Request

由于包含语法错误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。

402 Payment Required

该状态码是为了将来可能的需求而预留的。

403 Forbidden

服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个HEAD请求,而且服务器希望能够讲清楚为何请求不能被执行,就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,加入它不希望让客户端获得任何信息。

404 Not Found

请求失败,请求所希望得到的资源未在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是以永久的。假如服务器知道情况,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久不可使用,而且没有任何可以跳转的地址,404这个状态码被广泛应用于当服务器不想揭示为何请求被拒绝,或者没有其它适合的响应可用的情况下。

405 Method Not Allowed

请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow头信息,用以表示出当前资源能够接受的请求方法的列表。

鉴于PUT,DELETE方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者默认配置下不支持上述请求方法,对于此类请求均会返回405错误。

406 Not Acceptable

请求的资源的内容特性无法满足请求头中的条件,因为无法生成响应实体。

除非这是一个HEAD请求,否则该响应就应当返回一个包含可以让用户或浏览器从中选择最合适的实体特性及地址列表的实体。实体的格式由Content-Type头中定义的媒体类型决定。浏览器可以根据格式及自身能力自行做出最佳选择。但是,规范中并没有定义任何做出此类自动选择的标准。

408 Request Timeout

请求超时,客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。