nginx 指令
nginx rewrite 指令
nginx通过ngx_http_rewrite_module模块支持url重写、支持if条件判断,但不支持else。
该模块需要PCRE支持,应在编译nginx时指定PCRE源码目录, nginx安装方法。
nginx rewrite指令执行顺序:
1.执行server块的rewrite指令(这里的块指的是server关键字后{}包围的区域,其它xx块类似)
2.执行location匹配
3.执行选定的location中的rewrite指令
如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件
如果循环超过10次,则返回500 Internal Server Error错误
break指令
语法:break;
默认值:无
作用域:server,location,if
停止执行当前虚拟主机的后续rewrite指令集
break指令实例:
1
2
3
4
|
if ($slow) {
limit_rate 10k;
break;
}
|
if指令
语法:if(condition){...}
默认值:无
作用域:server,location
对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行。
if条件(conditon)可以是如下任何内容:
- 一个变量名;false如果这个变量是空字符串或者以0开始的字符串;
- 使用= ,!= 比较的一个变量和字符串
- 是用~, ~*与正则表达式匹配的变量,如果这个正则表达式中包含},;则整个表达式需要用" 或' 包围
- 使用-f ,!-f 检查一个文件是否存在
- 使用-d, !-d 检查一个目录是否存在
- 使用-e ,!-e 检查一个文件、目录、符号链接是否存在
- 使用-x , !-x 检查一个文件是否可执行
if指令实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
if($http_user_agent~MSIE){
rewrite^(.*)$/msie/$1break;
}
if($http_cookie~*"id=([^;]+)(?:;|$)"){
set$id$1;
}
if($request_method=POST){
return405;
}
if($slow){
limit_rate10k;
}
if($invalid_referer){
return403;
}
|
return指令
语法:return code;
return code URL;
return URL;
默认值:无
作用域:server,location,if
停止处理并返回指定状态码(code)给客户端。
非标准状态码444表示关闭连接且不给客户端发响应头。
从0.8.42版本起,return 支持响应URL重定向(对于301,302,303,307),或者文本响应(对于其他状态码).
对于文本或者URL重定向可以包含变量
rewrite指令
语法:rewrite regex replacement [flag];
默认值:无
作用域:server,location,if
如果一个URI匹配指定的正则表达式regex,URI就按照replacement重写。
rewrite按配置文件中出现的顺序执行。flags标志可以停止继续处理。
如果replacement以"http://"或"https://"开始,将不再继续处理,这个重定向将返回给客户端。
flag可以是如下参数
last 停止处理后续rewrite指令集,然后对当前重写的新URI在rewrite指令集上重新查找。
break 停止处理后续rewrite指令集,并不在重新查找,但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行。
redirect 如果replacement不是以http:// 或https://开始,返回302临时重定向
permant 返回301永久重定向
最终完整的重定向URL包括请求scheme(http://,https://等),请求的server_name_in_redirect和 port_in_redirec三部分 ,说白了也就是http协议 域名 端口三部分组成。
rewrite实例
1
2
3
4
5
6
7
|
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错误:
1
2
3
4
5
|
location/download/{
rewrite^(/download/.*)/media/(.*)..*$$1/mp3/$2.mp3break;
rewrite^(/download/.*)/audio/(.*)..*$$1/mp3/$2.rabreak;
return403;
}
|
对于重写后的URL(replacement)包含原请求的请求参数,原URL的?后的内容。如果不想带原请求的参数 ,可以在replacement后加一个问号。如下,我们加了一个自定义的参数user=$1,然后在结尾处放了一个问号?,把原请的参数去掉。
1
|
rewrite^/users/(.*)$/show?user=$1?last;
|
如果正则表达regex式中包含 “}
” 或 “;
”, 那么整个表达式需要用双引号或单引号包围.
rewrite_log指令
语法:rewrite_log on|off;
默认值:rewrite_log off;
作用域:http,server,location,if
开启或关闭以notice级别打印rewrite处理日志到error log文件。
nginx打开rewrite log例子
rewrite_log on;
error_log logs/xxx.error.log notice;
1.打开rewrite on
2.把error log的级别调整到 notice
set指令
语法:set variable value;
默认值:none
作用域:server,location,if
定义一个变量并赋值,值可以是文本,变量或者文本变量混合体。
uninitialized_variable_warn指令
语法:uninitialized_variable_warn on | off;
默认值:uninitialized_variable_warn on
作用域:http,server,location,if
控制是否输出为初始化的变量到日志
Location配置与ReWrite语法
1 Location语法规则
1.1 Location规则
语法规则: location [=|~|~*|^~] /uri/ {… }
首先匹配 =,其次匹配^~,其次是按文件中顺序的正则匹配,最后是交给 /通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
符号 |
含义 |
= |
= 开头表示精确匹配 |
^~ |
^~开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格) |
~ |
~ 开头表示区分大小写的正则匹配 |
~* |
~* 开头表示不区分大小写的正则匹配 |
!~和!~* |
!~和!~*分别为区分大小写不匹配及不区分大小写不匹配的正则 |
/ |
用户所使用的代理(一般为浏览器) |
$http_x_forwarded_for |
可以记录客户端IP,通过代理服务器来记录客户端的ip地址 |
$http_referer |
可以记录用户是从哪个链接访问过来的 |
匹配规则示例:
- location = / {
- #规则A
- }
- location = /login {
- #规则B
- }
- location ^~ /static/ {
- #规则C
- }
- location ~ \.(gif|jpg|png|js|css)$ {
- #规则D
- }
- location ~* \.png$ {
- #规则E
- }
- location !~ \.xhtml$ {
- #规则F
- }
- location !~* \.xhtml$ {
- #规则G
- }
- location / {
- #规则H
- }
那么产生的效果如下:
1. 访问根目录/,比如http://localhost/将匹配规则A
2. 访问 http://localhost/login 将匹配规则B,http://localhost/register则匹配规则H
3. 访问 http://localhost/static/a.html 将匹配规则C
4. 访问 http://localhost/a.gif,http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而http://localhost/static/c.png则优先匹配到规则C
5. 访问 http://localhost/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
6. 访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
7. 访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(PHP),tomcat(jsp),nginx作为方向代理服务器存在。
1.2 实际常用规则
#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
- location = / {
- proxy_passhttp://tomcat:8080/index
- }
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
- location ^~ /static/ {
- # 请求/static/a.txt 将被映射到实际目录文件:/webroot/res/static/a.txt
- root /webroot/res/;
- }
- location ~* \.(gif|jpg|jpeg|png|css|js|ico)${
- root /webroot/res/;
- }
#第三个规则就是通用规则,用来转发动态请求到后端应用服务器
#非静态文件请求就默认是动态请求,自己根据实际把握
#毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
- location / {
- proxy_pass http://tomcat:8080/
- }
1.3 Location解析过程
总结:
1、 先判断精准命中,如果命中,立即返回结果并结束解析过程。
2、 判断普通命中,如果有多个命中,“记录”下来“最长”的命中结果(记录但不结束,最长的为准)。
3、 继续判断正则表达式的解析结果,按配置里的正则表达式顺序为准,由上至下开始匹配,一旦匹配成功1个,立即返回结果,并结束解析过程。
4、 普通命中顺序无所谓,是因为按命中的长短来确定。正则命中,顺序有所谓,因为是从前入往后命中的。
2 ReWrite语法
Nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在server{},location{},if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用。
Rewrite主要的功能就是实现URL的重写,Nginx的Rewrite规则采用Pcre,perl兼容正则表达式的语法规则匹配,如果需要Nginx的Rewrite功能,在编译Nginx之前,需要编译安装PCRE库。
通过Rewrite规则,可以实现规范的URL、根据变量来做URL转向及选择配置。
2.1 ReWrite相关指令
指令 |
默认值 |
使用范围 |
作用 |
break |
none |
if,server,location |
完成当前的规则集,不再处理rewrite指令,需要和last加以区分 |
if ( condition ) { ... } |
none |
server,location |
用于检测一个条件是否符合,符合则执行大括号内的语句。不支持嵌套,不支持多个条件&&或||处理 |
return |
none |
server,if,location |
用于结束规则的执行和返回状态码给客户端。状态码的值可以是:204,400,402~406,408,410,411,413,416以及500~504,另外非标准状态码444,表示以不发送任何的Header头来结束连接。 |
rewrite regex replacement flag |
|
server,location,if |
该指令根据表达式来重定向URI,或者修改字符串。指令根据配置文件中的顺序来执行。注意重写表达式只对相对路径有效。 |
uninitialized_variable_warn on|off |
on |
http,server,location,if |
该指令用于开启和关闭未初始化变量的警告信息,默认值为开启。 |
set variable value |
none |
|
该指令用于定义一个变量,并且给变量进行赋值。变量的值可以是文本、一个变量或者变量和文本的联合,文本需要用引号引起来。 |
2.2 Rewrite全局变量
rewrite全局变量表
变量 |
含义 |
$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相同。 |
2.3 Rewrite语法规则
操作符 |
含义 |
= ,!= |
比较的一个变量和字符串。 |
~, ~* |
与正则表达式匹配的变量,如果这个正则表达式中包含},;则整个表达式需要用"或'包围。 |
-f,!-f |
检查一个文件是否存在。 |
-d, !-d |
检查一个目录是否存在。 |
-e,!-e |
检查一个文件、目录、符号链接是否存在。 |
-x, !-x |
检查一个文件是否可执行。 |
2.4 if指令
- if 语法格式
- if 空格 (条件) {
- 重写模式
- }
- # 限制浏览器访问
- if ($http_user_agent ~ Firefox) {
- rewrite ^(.*)$ /firefox/$1 break;
- }
- if ($http_user_agent ~ MSIE) {
- rewrite ^(.*)$ /msie/$1 break;
- }
- if ($http_user_agent ~ Chrome) {
- rewrite ^(.*)$ /chrome/$1 break;
- }
2.5 return指令
- # 限制IP访问
- if ($remote_addr = 192.168.197.142) {
- return 403;
- }
2.6 rewrite指令
#判断目录是否存在
#服务器内部的rewrite和302跳转不一样.跳转的话URL都变了,变成重新http请求index.html,而内部rewrite,上下文没变。
- if (!-e $document_root$fastcgi_script_name) {
- rewrite ^.*$ /index.html break;
- }
2.7 set指令
# set指令是设置变量用的,可以用来达到多条件判断时作标志用
#判断IE并重写,且不用break;我们用set变量来达到目的
- if ($http_user_agent ~* msie) {
- set $isie 1;
- }
- if ($fastcgi_script_name = ie.html) {
- set $isie 0;
- }
- if ($isie 1) {
- rewrite ^.*$ ie.html;
- }
2.8 常用正则
-
.
: 匹配除换行符以外的任意字符 -
?
: 重复0次或1次 -
+
: 重复1次或更多次 -
*
: 重复0次或更多次 -
\d
:匹配数字 -
^
: 匹配字符串的开始 -
$
: 匹配字符串的末尾 -
{n}
: 重复n次 -
{n,}
: 重复n次或更多次 -
[c]
: 匹配单个字符c -
[a-z]
: 匹配a-z小写字母的任意一个
小括号()
之间匹配的内容,可以在后面通过$1
来引用,$2
表示的是前面第二个()
里的内容。正则里面容易让人困惑的是\
转义特殊字符。
1 http { 2 # 定义image日志格式 3 log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status; 4 # 开启重写日志 5 rewrite_log on; 6 7 server { 8 root /home/www; 9 10 location / { 11 # 重写规则信息 12 error_log logs/rewrite.log notice; 13 # 注意这里要用‘’单引号引起来,避免{} 14 rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4; 15 # 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行 16 set $image_file $3; 17 set $image_type $4; 18 } 19 20 location /data { 21 # 指定针对图片的日志格式,来分析图片类型和大小 22 access_log logs/images.log mian; 23 root /data/images; 24 # 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里 25 try_files /$arg_file /image404.html; 26 } 27 location = /image404.html { 28 # 图片不存在返回特定的信息 29 return 404 "image not found\n"; 30 } 31 }
对形如/images/ef/uh7b3/test.png
的请求,重写到/data?file=test.png
,于是匹配到location /data
,先看/data/images/test.png
文件存不存在,如果存在则正常响应,如果不存在则重写tryfiles到新的image404
location,直接返回404状态码。
例2:
1
|
rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;
|
对形如/images/bla_500x400.jpg
的文件请求,重写到/resizer/bla.jpg?width=500&height=400
地址,并会继续尝试匹配location。