1、rewirte模块(ngx_http_rewrite_module)
1.1 介绍
该模块允许使用正则表达式改变URI,并且根据变量来跳转以及选择配置。rewirte的循环最多会执行10次,然后Nginx会返回一个500错误。
1.2 常用正则
. : 匹配除换行符以外的任意字符
? : 重复0次或1次
+ : 重复1次或更多次
* : 重复0次或更多次
\d :匹配数字
^ : 匹配字符串的开始
$ : 匹配字符串的介绍
{n} : 重复n次
{n,} : 重复n次或更多次
[c] : 匹配单个字符c
[a-z] : 匹配a-z小写字母的任意一个
1.3 全局变量
下面是可以用作if判断的全局变量:
$args : #这个变量等于请求行中的参数,同$query_string
$content_length : 请求头中的Content-length字段。
$content_type : 请求头中的Content-Type字段。
$document_root : 当前请求在root指令中指定的值。
$host : 请求主机头字段,否则为服务器名称。
$http_user_agent : 客户端agent信息
$http_cookie : 客户端cookie信息
$limit_rate : 这个变量可以限制连接速率。
$request_method : 客户端请求的动作,通常为GET或POST。
$remote_addr : 客户端的IP地址。
$remote_port : 客户端的端口。
$remote_user : 已经经过Auth Basic Module验证的用户名。
$request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
$scheme : HTTP方法(如http,https)。
$server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
$server_name : 服务器名称。
$server_port : 请求到达服务器的端口号。
$request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
$document_uri : 与$uri相同。
示例:http://localhost:88/test1/test2/test.php这个URL,
$host:localhost
$server_port:88
$request_uri:http://localhost:88/test1/test2/test.php
$document_uri:/test1/test2/test.php
$document_root:/var/www/html
$request_filename:/var/www/html/test1/test2/test.php
2、rewirte常用模块指令
2.1 break
- 语法:break
- 默认值:none
- 作用域:server,location,if
- 作用:此指令的意思是停止执行当前虚拟主机的后续rewrite指令集
- 示例:限速,$slow可以通过 set 指令设置
if ($slow) {
limit_rate 10k;
break;
}
2.2 if
- 语法:if (condition) { … }
- 默认值:none
- 作用域:server,location
- 作用:对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行。
- if条件(conditon)可以是如下任何内容: ```html
- 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false;
- 使用“=”和“!=”比较一个变量和字符串;
- 使用“~”做正则表达式匹配,“~”做不区分大小写的正则匹配,“!~”做区分大小写的正则不匹配;!~做不区分大小写的正则不匹配;
- 使用“-f”和“!-f” 检查一个文件是否存在;
- 使用“-d”和“!-d”检查一个目录是否存在;
- 使用“-e”和“!-e”检查一个文件、目录、符号链接是否存在;
- 使用“-x”和“ !-x”检查一个文件是否可执行; ```
示例:
# 如果UA包含"MSIE",rewrite请求到/msid/目录下
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
# 如果cookie匹配正则,设置变量$id等于正则引用部分
if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
set $id $1;
}
# 如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302
if ($request_method = POST ) {
return 405;
}
# 如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查
if (!-f $request_filename) {
break;
proxy_pass http://127.0.0.1;
}
# 限速,$slow可以通过 set 指令设置
if ($slow) {
limit_rate 10k;
}
# 给某个访问IP返回403
if ( $remote_addr = "202\.38\.78\.85" ){
return 403;
}
# 防盗链
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.baidu.com www.ywnds.com;
if ($invalid_referer) {
return 404;
}
}
2.3 return
- 语法:return code
- 默认值:none
- 作用域:server, location, if
作用:这个指令根据规则的执行情况,返回一个状态值给客户端。可使用值包括:204,400,402-406,408,410,411,413,416以及500-504。也可以发送非标准的444代码-未发送任何头信息下结束连接。
2.4 rewrite
语法:rewrite regex replacement [flag];
- 默认值:none
- 作用域:server, location, if
- 作用:rewrite指令的功能就是,使用nginx提供的全局变量或自己设置的变量,然后结合正则表达式和标志位实现url重写以及重定向。指令根据配置文件中的顺序来执行。只对域名后边的除去传递的参数外的字符串起作用,例如 http://ywnds.com/a/we/index.php?id=1&u=str,只对/a/we/index.php重写。
- 如果想对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。
示例:
# www.mydomain.com/foo 跳转到 mydomain.com/foo
if ($host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1代表括号里的内容
}
2.5 set
- 语法:set variable value
- 默认值:none
- 作用域:server, location, if
作用:定义一个变量并赋值,值可以是文本,变量或者文本变量混合体
3.flag标识位
3.1 标识位种类
last,完成该rewrite规则的执行后,停止处理后续rewrite指令集,然后查找匹配改变后URI的新location;
- break,完成该rewrite规则的执行后,停止处理后续rewrite指令集,并不再重新查找;但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行;
- redirect,返回302临时重定向,地址栏会显示跳转后的地址;
permanent,返回301永久重定向,地址栏会显示跳转后的地址;即表示如果客户端不清理浏览器缓存,那么返回的结果将永久保存在客户端浏览器中了。
3.2 last和break区别
因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里last和break区别有点难以理解:
last一般写在server和if中,而break一般使用在location中;
- last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配;
- break和last都能阻止继续执行后面的rewrite指令。
4、示例
4.1 示例1:last和break区别
/download/api/media/test.txt 跳转到/download/api/mp3/test.mp3
server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
...
}
如果这些rewrite放到“/download/”路径,那么location如下所示,这时应使用break而不是last,使用last将循环10次匹配,然后返回500错误:
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;
return 403;
}
4.2 示例2:去除原请求中的请求参数
对于重写后的URL(replacement)包含原请求的请求参数,原URL的?后的内容。如果不想带原请求的参数,可以在replacement后加一个问号。如下,我们加了一个自定义的参数user=$1,然后在结尾处放了一个问号?,把原请求的参数去掉。
rewrite ^/users/(.*)$ /show?user=$1? last;
4.3 示例3: 正则内带特殊符号{}
对花括号“}”或“;”来说,使用时需要用双引号或单引号包围。因为他们既能用在重定向的正则表达式里,也是用在配置文件里分割代码块, 为了避免冲突, 正则表达式里带花括号的话,应该用双引号(或者单引号)包围。比如,要将类似以下的URI:”/photos/123456″重定向到”/path/to/photos/12/1234/123456.png”可以用以下方法 (注意双引号):
rewrite "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png;
4.4 示例4:http跳转到https
访问www.a.com跳转到https://www.a.com
rewrite (.*) https://www.a.com/$1 permanent
还可以这样写:
server {
listen 80;
server_name www.a.com;
return 301 https://$server_name$request_uri;
}
4.5 示例5:将uri某部分作为参数传给后端
www.a.com/todo/34跳转为www.a.com/todo?id=34
rewrite ^/todos/(.*) /todos?id=$1 break;