Nginx rewrite深入解读
1.什么是rewrite
官方解读:nginx的重写模块(rewrite)是一个简单的正则表达式匹配与一个虚拟堆叠机结合。
个人解读:nginx的rewrite是结合正则表达式和标志位实现url重写、改变以及重定向。如:域名跳转,防盗链,反向代理,各种跳转(跳转维护界面,前端跳转,基于uri跳转,基于目录跳转等)
2.rewrite的支撑源头
nginx通过ngx_http_rewrite_module模块支持url重写、支持if条件判断。依赖于PCRE库,因此需要安装pcre。
3.rewrite的7个指令
3.1.break
- 语法:break
- 默认值:none
- 配置段:server,location,if
- 作用:完成当前设置的重写规则,停止处理后续rewrite指令集,并不在重新查找,但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行。
- 实例:
if ($slow) {
limit_rate 10k;
break;
}
3.2.if
- 语法:if(condition){…}
- 默认值:none
- 配置段:server,location
- 作用:对给定的条件condition进行判断
- conditon:if条件(conditon)可以是如下任何内容:
- 一个变量名:空字符传“ ”或者一些“0”开始的字符串为false
- 字符串比较:使用=或!=运算符
- 正则表达式匹配:用~或~*+正则表达式匹配的变量,如果这个正则表达式中包含}或;,则整个表达式需要用” 或’ 包围
- 文件是否存在:使用-f或者!-f操作符
- 目录是否存在:使用-d或者!-d操作符
- 文件、目录、符号链接是否存在:使用-e或者!-e操作符
- 文件是否可执行:使用-x或者!-x操作符
- 实例:
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1
break;
}
3.3.return
- 语法:
- return code;
- return url;
- return code url;
- 默认值:none
- 配置段:server,location,if
- 作用:
- 停止处理,并为客户端返回状态码。
- 非标准的444状态码将关闭连接,不发送任何响应头
- 可以使用的状态码有:204/400/402-406/408/410/411/413/416/500-504
- 如果状态码后面是一个url,该url将成为location头的补值。
- 没有状态码的url将被视为一个默认的302状态码
- 状态码附带文字段落,该文本将被放置在响应主体里
- 实例:
if ($request_method = POST) {
return 405;
}
if ($invalid_referer) {
return 403;
}
3.4.rewrite
- 语法:rewrite regex replacement [flag];
- 默认值:none
- 配置段:server,location,if
- 作用:
- 如果一个URI匹配指定的正则表达式regex,URI就按照replacement重写
- 可以在重写指令后添加标识【flag】
- flag标志可以停止继续处理
- 如果replacement以”http://”或”https://”开始,将不再继续处理rewrite指令,这个重定向将返回给客户端
- flag标识符可为以下值:
- last:停止处理后续rewrite指令集,然后对当前重写的新URI在rewrite指令集上重新查找。
- break:完成rewrite指令,并不在重新查找,但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行。
- redirect:如果replacement不是以http:// 或https://开始,返回302临时重定向
- permannet:返回301永久重定向
- 最终完整的重定向URL包括请求scheme(http://,https://等),请求的server_name_in_redirect和 port_in_redirec三部分 ,说白了也就是http协议 域名 端口三部分组成。
- 实例:
location /download/ {
rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra break;
return 403;
}
3.5.rewrite_log
- 语法:rewrite_log on|off;
- 默认值:rewrite_log off;
- 配置段:http,server,location,if
- 作用:启用时将在error log中记录notice级别的重写日志
- 实例:
rewrite_log on;
error_log logs/xxx.error.log notice;
3.6.set
- 语法:set variable value;
- 默认值:none
- 配置段:server,location,if
- 作用:定义一个变量并赋值,值可以是文本,变量或者文本变量混合体。
3.7.uninitialized_variable_warn
- 语法:uninitialized_variable_warn on | off;
- 默认值:uninitialized_variable_warn on
- 作用域:http,server,location,if
- 作用:控制是否记录未初始化的警告信息
4.rewrite的规则
4.1.rewrite指令执行顺序
- 执行server块的rewrite指令(这里的块指的是server关键字后{}包围的区域,其它xx块类似)
- 执行location匹配
- 执行选定的location中的rewrite指令
- 如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件
如果循环超过10次,则返回500 Internal Server Error错误
4.2.正则表达式-引用取值
- 可以使用括号来捕获,后续可用位置来将其引用,位置变量取决于捕获正则表达式中的顺序, 1引用第一个括号()中值, 2则引用第二个括号中的值
- 实例:
^/img/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|gif|jpg)$
1)
1:是([a−z]2),两个小写字母组成的字符串2)
2:是([a-z0-9]{5}),由小写字母或0-9组成的5个字符串
3)
3:是(.∗),是文件名4)
4:是(png|gif|jpg),其中一个
4.3.return返回规则
- 停止处理,并为客户端返回状态码。
- 非标准的444状态码将关闭连接,不发送任何响应头
- 可以使用的状态码有:204/400/402-406/408/410/411/413/416/500-504
- 如果状态码后面是一个url,该url将成为location头的补值。
- 没有状态码的url将被视为一个默认的302状态码
- 状态码附带文字段落,该文本将被放置在响应主体里
location = /img404.html{
return 404 "image not found\n";
}
5.rewrite小实例
5.1.禁止.sh .bash
location ~ .*\.(sh|bash)?${
return 403;
}
5.2.目录跳转
location /a{
alias /data/site/b.chen.com/a;
rewrite ^/a/?$ /b last;
}
location /b{
alias /data/site/b.chen.com/b;
default_type 'text/html';
echo "url is a -> rewrite to b...";
}
5.3.防盗链实例
5.3.0.valid_referer指令说明
Nginx配置中有一个指令valid_referers,用来获取Referer头域中的值,并且根据该值的情况给Nginx全局变量
invalidreferer的值,如果Referer头域中没有符合validreferers指令配置的值,
invalid_referer变量将会被赋值为1。
valid_referer指令的语法结构为:
valid_referers none | blocked | server_names | string ....;
none 检测Referer头域不存在的请求
blocked 检测Referer头域的值被防火墙或者代理服务器删除或伪装的情况。
这种情况下,该头域的值不以“http://”或者“https://”开头
server_names 设置一个或多个URL,检测Referer头域的值是否是这些URL中的某个。
从nginx 0.5.33以后支持使用通配符“*”。
5.3.1.nginx.conf的server配置
server{
server_name echo.chen.com;
listen 80;
location /{
root /data/site/echo.chen.com;
index index.html;
}
location ~ .*\.(jpg|png)$ {
valid_referers none blocked echo.chen.com;
if ($invalid_referer) {
return 412;
break;
}
root /data/site/echo.chen.com;
}
location =/error.html{
root /data/site/echo.chen.com;
}
}
- /data/site/echo.chen.com 自行创建目录
- index.html内容如下:
this is index.html
<img src="http://echo.chen.com/1.jpg">
5.3.2.Windows下host配置
192.168.1.111 b.chen.com
192.168.1.111 echo.chen.com
- 配置不同域名指定同一个ip,以便测试
5.3.3.浏览器测试
访问指定的域名,即可访问到图片
使用b.chen.com进行访问则不能访问到服务器图片
5.4.域名跳转
server{
server_name jump.chen.com;
listen 80;
access_log off;
location /{
default_type "text/html";
echo "it is echo.chen.com jump to jump.chen.com";
}
}
server{
server_name echo.chen.com;
listen 80;
rewrite ^/ http://jump.chen.com/;
location /{
}
}