这里不讨论rewrite中的配置, 不讨论nginx的其他配置
rewrite: 使用nginx提供的全局变量或自定义变量,结合正则表达式和标志位实现url重写以及重定向。
rewrite只能放在配置文件的server{ }
,location{}
,if{}
中,并且只能对域名后面(或者叫路径, 不包含请求参数(query string
))的字符串起作用。
例如: http://www.domain.com/a/b/index.html?id=1&page=2
只对 /a/b/index.html 重写。
如果想对域名或请求参数(
query string
)起作用,可使用全局变量匹配,也可以使用proxy_pass
反向代理。
- 语法:rewrite regex replacement [flag];
- 默认值:无
- 作用域:server,location,if
如果一个URI
匹配指定的正则表达式regex
,URI
就按照replacement
重写。
rewrite
按配置文件中出现的顺序执行,flags标志可以停止继续处理。
如果replacement
以 "http://" 或 "https://" 开始,将不再继续处理,这个重定向将返回给客户端。
rewrite指令执行顺序
- 执行
server
块的rewrite
指令(这里的块指的是server关键字后{}包围的区域,其它xx块类似) - 执行
location
匹配 - 执行选定的
location
中的rewrite
指令
如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error
错误。
rewrite
和location
功能有点像,都能实现跳转,区别在于:
rewrite
是在同一域名内更改获取资源的路径location
是对一类路径做控制访问或反向代理,可以proxy_pass
到其他机器。
很多情况下rewrite也会写在location里.
rewrite实例:
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;
}
对于重写后的 URL
(replacement
)包含原请求的请求参数
(query string
),即原URL
的?
后的内容。如果不想带原请求的参数 ,可以在replacement
后加一个问号
。如下,我们加了一个自定义的参数user=$1
, 然后在结尾处放了一个问号?
, 把原请的参数去掉:
rewrite ^/users/(.*)$ /show?user=$1? last;
flag 标志位
flag
可以是如下参数:
- last 停止处理后续
rewrite
指令集,然后对当前重写的新URI
在rewrite
指令集上重新查找。相当于Apache
的[L]
标记 - break 停止处理后续
rewrite
指令集,并不再重新查找, 但是当前location
内剩余非rewrite
语句和location
外的的非rewrite
语句可以执行。 - redirect 如果
replacement
不是以"http://" 或 "https://" 开头,返回302临时重定向,地址栏会显示跳转后的地址 - permant 返回301永久重定向,地址栏会显示跳转后的地址
在rewrite
中last
和 break
的区别:
last
一般写在server
和if
段中,而break
一般使用在location
段中last
不终止重写后的url匹配,即新的url
会再从server
走一遍匹配流程,而break
终止重写后的匹配break
和last
都能组织继续执行后面的rewrite
指令
最终完整的重定向URL包括请求scheme
(http://, https:// 等), 请求的server_name_in_redirect
和 port_in_redirec
三部分 ,说白了也就是http协议 域名 端口三部分组成。
if指令与全局变量
if指令
语法:if(condition){...}
默认值:无
作用域:server
, location
对给定的条件condition
进行判断。如果为真,大括号内的rewrite
指令将被执行。
if条件(conditon
)可以是如下任何内容:
- 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做 (bool)false
- 直接比较变量和内容时,使用
=
或!=
~
正则表达式匹配,~*
不区分大小写的匹配,!~
区分大小写的不匹配. 如果这个正则表达式中包含}
,
;
则整个表达式需要用双引号" 或 单引号' 包围-f
和!-f
用来判断是否存在文件-d
和!-d
用来判断是否存在目录-e
和!-e
用来判断是否存在文件或目录-x
和!-x
用来判断文件是否可执行
e.g:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite请求到/msid/目录下
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
} //如果cookie匹配正则,设置变量$id等于正则引用部分
if ($request_method = POST) {
return 405;
} //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302
if ($slow) {
limit_rate 10k;
} //限速,$slow可以通过 set 指令设置
if (!-f $request_filename){
break;
proxy_pass http://127.0.0.1;
} //如果请求的文件名不存在,则反向代理到localhost 。这里的break会停止rewrite检查
if ($args ~ post=140){
rewrite ^ http://example.com/ permanent;
} //如果query string中包含"post=140",永久重定向到example.com
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.jefflei.com www.leizhenfang.com;
if ($invalid_referer) {
return 404;
} //防盗链
}
全局变量
- $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,如”/foo/bar.html”。
- $document_uri : 与$uri相同。
正则匹配
- . : 匹配除换行符以外的任意字符
- ? : 重复0次或1次
- + : 重复1次或更多次
- * : 重复0次或更多次
- {n} : 重复n次
- {n,} : 重复n次或更多次
- \d :匹配数字
- ^ : 匹配字符串的开始
- $ : 匹配字符串的介绍
- [c] : 匹配单个字符c
- [a-zA-Z0-9] : 匹配a-z小写字母,A-Z大写字母, 数字0-9 中的任意一个
- (jpg|png) : 匹配字符串 jpg 或 png , 括号表示分组
小括号()
之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容
rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
set $file_name_without_ext $3;
set $file_ext $4;
对形如 /images/ef/202103/test.png 的请求,重写到 /data?file=test.png
rewrite规则中如果要忽略大小写, 可以使用 (?i)
这个与用"/"开始结尾的javascript/php等语言的reg pattern使用/i是不同的.
rewrite ^(.*)_(middle|small)(\.(?i)(jpg|jpeg|png|gif))$ /thumb_fixed.php break;
这个规则把 xxx_middle.jpg, xxx_middle.JPG, xxx_small.png, xxx_small.PNG 这样的图片地址进行了重写