Nginx的rewrite模块详解


Posted in Servers onMarch 31, 2021

rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配location,或者直接做30x重定向返回客户端。

指令执行顺序
首先顺序执行server块中的rewrite模块指令,得到rewrite后的请求URI
然后循环执行如下指令

如果没有遇到中断循环标志,此循环最多执行10次,但是我们可以使用break指令来中断rewrite后的新一轮的循环
(1). 依据rewrite后的请求URI,匹配定义的 location 块

(2). 顺序执行匹配到的 location 中的rewrite模块指令

指令
break
Context: server, location, if
停止执行 ngx_http_rewrite_module 的指令集,但是其他模块指令是不受影响的

例子说明

server {
 listen 8080;
 # 此处 break 会停止执行 server 块的 return 指令(return 指令属于rewrite模块)
 # 如果把它注释掉 则所有请求进来都返回 ok
 break;
 return 200 "ok";
 location = /testbreak {
  break;
  return 200 $request_uri;
  proxy_pass http://127.0.0.1:8080/other;
 }
 location / {
  return 200 $request_uri;
 }
}

# 发送请求如下
# curl 127.0.0.1:8080/testbreak
# /other

# 可以看到 返回 `/other` 而不是 `/testbreak`,说明 `proxy_pass` 指令还是被执行了
# 也就是说 其他模块的指令是不会被 break 中断执行的
# (proxy_pass是ngx_http_proxy_module的指令)

if
Context: server, location

依据指定的条件决定是否执行 if 块语句中的内容

if 中的几种 判断条件
1.一个变量名,如果变量 $variable 的值为空字符串或者字符串"0",则为false
2.变量与一个字符串的比较 相等为(=) 不相等为(!=) 注意此处不要把相等当做赋值语句啊
3.变量与一个正则表达式的模式匹配 操作符可以是(~ 区分大小写的正则匹配, ~不区分大小写的正则匹配, !!,前面两者的非)
4.检测文件是否存在 使用 -f(存在) 和 !-f(不存在)
5.检测路径是否存在 使用 -d(存在) 和 !-d(不存在) 后面判断可以是字符串也可是变量
6.检测文件、路径、或者链接文件是否存在 使用 -e(存在) 和 !-e(不存在) 后面判断可以是字符串也可是变量
7.检测文件是否为可执行文件 使用 -x(可执行) 和 !-x(不可执行) 后面判断可以是字符串也可是变量

注意 上面 第1,2,3条被判断的必须是 变量, 4, 5, 6, 7则可以是变量也可是字符串, -f/-d/-e/-x 基本用法和 bash 是一致的.

set $variable "0"; 
if ($variable) {
 # 不会执行,因为 "0" 为 false
 break;   
}

# 使用变量与正则表达式匹配 没有问题
if ( $http_host ~ "^star\.igrow\.cn$" ) {
 break;   
}

# 字符串与正则表达式匹配 报错
if ( "star" ~ "^star\.igrow\.cn$" ) {
 break;   
}
# 检查文件类的 字符串与变量均可
if ( !-f "/data.log" ) {
 break;   
}

if ( !-f $filename ) {
 break;   
}

return

Context: server, location, if
return code [text];
return code URL;
return URL;

停止处理并将指定的code码返回给客户端。 非标准code码 444 关闭连接而不发送响应报头。

从0.8.42版本开始, return 语句可以指定重定向 url (状态码可以为如下几种 301,302,303,307),
也可以为其他状态码指定响应的文本内容,并且重定向的url和响应的文本可以包含变量。

有一种特殊情况,就是重定向的url可以指定为此服务器本地的urI,这样的话,nginx会依据请求的协议$scheme, server_name_in_redirect 和 port_in_redirect自动生成完整的 url (此处要说明的是server_name_in_redirect 和port_in_redirect 指令是表示是否将server块中的 server_name 和 listen 的端口 作为redirect用 )

# return code [text]; 返回 ok 给客户端
location = /ok {
 return 200 "ok";
}

# return code URL; 临时重定向到 百度
location = /redirect {
 return 302 http://www.baidu.com;
}

# return URL; 和上面一样 默认也是临时重定向
location = /redirect {
 return http://www.baidu.com;
}

rewrite

Context: server, location, if

rewrite regex replacement [flag];

rewrite 指令是使用指定的正则表达式regex来匹配请求的urI,如果匹配成功,则使用replacement更改URI。rewrite指令按照它们在配置文件中出现的顺序执行。可以使用flag标志来终止指令的进一步处理。如果替换字符串replacement以http://,https://或$ scheme开头,则停止处理后续内容,并直接重定向返回给客户端。

第一种情况 重写的字符串 带http://

location / {
 # 当匹配 正则表达式 /test1/(.*)时 请求将被临时重定向到 http://www.$1.com
 # 相当于 flag 写为 redirect
 rewrite /test1/(.*) http://www.$1.com;
 return 200 "ok";
}
# 在浏览器中输入 127.0.0.1:8080/test1/baidu 
# 则临时重定向到 www.baidu.com
# 后面的 return 指令将没有机会执行了

第二种情况 重写的字符串 不带http://

location / {
 rewrite /test1/(.*) www.$1.com;
 return 200 "ok";
}
# 发送请求如下
# curl 127.0.0.1:8080/test1/baidu
# ok

# 此处没有带http:// 所以只是简单的重写。请求的 uri 由 /test1/baidu 重写为 www.baidu.com
# 因为会顺序执行 rewrite 指令 所以 下一步执行 return 指令 响应了 ok

rewrite 的四个 flag

1.last
停止处理当前的ngx_http_rewrite_module的指令集,并开始搜索与更改后的URI相匹配的location; (因为 last 英文含义是"继续", 会继续尝试匹配跳转其他 location)
2.break
停止处理当前的ngx_http_rewrite_module指令集,就像上面说的break指令一样; (break 是"中断停止")
3.redirect
返回302临时重定向。(可以理解是"临时租房")
4.permanent
返回301永久重定向。(可以理解是"搬新家")

# 没有rewrite 后面没有任何 flag 时就顺序执行 
# 当 location 中没有 rewrite 模块指令可被执行时 就重写发起新一轮location匹配
location / {
 # 不加 flag, 默认顺序执行
 rewrite ^/test1 /test2;
 rewrite ^/test2 /test3; # 此处发起新一轮location匹配 uri为/test3
}

location = /test2 {
 return 200 "/test2";
} 

location = /test3 {
 return 200 "/test3";
}
# 发送如下请求
# curl 127.0.0.1:8080/test1
# /test3

last 与 break 的区别

last 和 break一样 它们都会终止此 location 中其他它rewrite模块指令的执行,
但是 last 立即发起新一轮的 location 匹配 而 break 则不会

location / {
 rewrite ^/test1 /test2;
 rewrite ^/test2 /test3 last; # 此处发起新一轮location匹配 uri为/test3
 rewrite ^/test3 /test4;
 proxy_pass http://www.baidu.com;
}

location = /test2 {
 return 200 "/test2";
} 

location = /test3 {
 return 200 "/test3";
}
location = /test4 {
 return 200 "/test4";
}
# 发送如下请求
# curl 127.0.0.1:8080/test1
# /test3 

当如果将上面的 location / 改成如下代码
location / {
 rewrite ^/test1 /test2;
 # 此处 不会 发起新一轮location匹配;当是会终止执行后续rewrite模块指令 重写后的uri为 /more/index.html
 rewrite ^/test2 /more/index.html break; 
 rewrite /more/index\.html /test4; # 这条指令会被忽略

 # 因为 proxy_pass 不是rewrite模块的指令 所以它不会被 break终止
 proxy_pass https://www.baidu.com;
}
# 发送如下请求
# 浏览器输入 127.0.0.1:8080/test1 
# 代理到 百度产品大全页面 https://www.baidu.com/more/index.html;

rewrite 后的请求参数
如果替换字符串replacement包含新的请求参数,则在它们之后附加先前的请求参数。如果你不想要之前的参数,则在替换字符串 replacement 的末尾放置一个问号,避免附加它们。

# 由于最后加了个 ?,原来的请求参数将不会被追加到rewrite之后的url后面 
rewrite ^/users/(.*)$ /show?user=$1? last;

rewrite_log

Context: http, server, location, if

开启或者关闭 rewrite模块指令执行的日志,如果开启,则重写将记录下notice 等级的日志到nginx 的 error_log 中,默认为关闭 off

Syntax: rewrite_log on | off;

set

Context: server, location, if

设置指定变量的值。变量的值可以包含文本,变量或者是它们的组合形式。

location / {
 set $var1 "host is ";
 set $var2 $host;
 set $var3 " uri is $request_uri";
 return 200 "response ok $var1$var2$var3";
}
# 发送如下请求
# curl 127.0.0.1:8080/test
# response ok host is 127.0.0.1 uri is /test

uninitialized_variable_warn

Context: http, server, location, if

控制是否记录 有关未初始化变量的警告。默认开启

内部实现

该ngx_http_rewrite_module模块指令是在配置阶段编译成被请求处理过程中解释内部指示。解释器是一个简单的虚拟堆栈机。

例如,指令

location /download/ { if ( f o r b i d d e n ) r e t u r n 403 ; i f ( forbidden) { return 403; } if ( forbidden)return403;if(slow) { limit_rate 10k; } rewrite ^/(download/.)/media/(.)…*$ /$1/mp3/$2.mp3 break; }

将被翻译成以下说明:

variable $forbidden check against zero return 403 end of code variable $slow check against zero match of regular expression copy “/” copy $1 copy “/mp3/” copy $2 copy “.mp3” end of regular expression end of code

请注意, 上面的limit_rate指令没有任何 指令,因为它与ngx_http_rewrite_module模块无关 。为if块创建一个单独的配置。如果条件成立,则将为此配置分配一个请求,该请求limit_rate等于10k。\

指令

rewrite ^/(download/.)/media/(.)…*$ /$1/mp3/$2.mp3 break;

如果正则表达式中的第一个斜杠放在括号内,则可以简化:

rewrite ^(/download/.)/media/(.)…*$ $1/mp3/$2.mp3 break;

相应的指令将如下所示:

match of regular expression copy $1 copy “/mp3/” copy $2 copy “.mp3” end of regular expression end of code

location (非 rewrite模块)

语法

在server块中使用,如:

  • server{
  • location 表达式 {
  • }

location表达式类型

如果直接写一个路径,则匹配该路径下的 表示执行一个正则匹配,区分大小写
~* 表示执行一个正则匹配,不区分大小写
^~ 表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location。
= 进行普通字符精确匹配。也就是完全匹配。

优先级
1.等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
2.^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
3.正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
4.常规字符串匹配类型。按前缀匹配。

到此这篇关于Nginx的rewrite模块详解的文章就介绍到这了,更多相关Nginx的rewrite内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Servers 相关文章推荐
小程序后台PHP版本部署运行 LNMP+WNMP
Apr 01 Servers
Nginx+Tomcat负载均衡集群的实现示例
Oct 24 Servers
Linux安装apache服务器的配置过程
Nov 27 Servers
NGINX 权限控制文件预览和下载的实现原理
Jan 18 Servers
Vertica集成Apache Hudi重磅使用指南
Mar 31 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
Windows Server 2019 配置远程控制以及管理方法
Apr 28 Servers
排查Tomcat进程假死的问题
May 06 Servers
Nginx 配置 HTTPS的详细过程
May 30 Servers
V Rising 服务器搭建图文教程
Jun 16 Servers
在虚拟机中安装windows server 2008的图文教程
Jun 28 Servers
搭建zabbix监控以及邮件报警的超级详细教学
Jul 15 Servers
nginx常用命令放入shell脚本详解
Mar 31 #Servers
详解如何修改nginx的默认端口
nginx前后端同域名配置的方法实现
Mar 31 #Servers
Nginx同一个域名配置多个项目的实现方法
Mar 31 #Servers
Apache压力测试工具的安装使用
Apache站点配置SSL强制跳转443
Mar 09 #Servers
使用Apache的rewrite
Mar 09 #Servers
You might like
php 分页原理详解
2009/08/21 PHP
利用PHP扩展vld查看PHP opcode操作步骤
2013/03/04 PHP
深入Nginx + PHP 缓存详解
2013/07/11 PHP
yiic命令时提示“php.exe”不是内部或外部命令的解决方法
2014/12/18 PHP
php实现监控varnish缓存服务器的状态
2014/12/30 PHP
PHP批量查询WordPress留言者E-mail地址实现方法
2015/02/15 PHP
YII框架中使用memcache的方法详解
2017/08/02 PHP
可以文本显示的公告栏的js代码
2007/03/11 Javascript
javascript学习笔记(十八) 获得页面中的元素代码
2012/06/20 Javascript
用原生JavaScript实现jQuery的$.getJSON的解决方法
2013/05/03 Javascript
javascript获取select的当前值示例代码(兼容IE/Firefox/Opera/Chrome)
2013/12/17 Javascript
基于jQuery通过jQuery.form.js插件实现异步上传
2015/12/13 Javascript
Jquery跨浏览器文本复制插件Zero Clipboard的使用方法
2016/02/28 Javascript
AngularJS中的按需加载ocLazyLoad示例
2017/01/11 Javascript
使用socket.io实现简单聊天室案例
2018/01/02 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
2018/01/23 Javascript
vue router动态路由下让每个子路由都是独立组件的解决方案
2018/04/24 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
2018/07/18 Javascript
JQuery 实现文件下载的常用方法分析
2019/10/29 jQuery
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
Taro小程序自定义顶部导航栏功能的实现
2020/12/17 Javascript
[04:38]完美世界携手游戏风云打造 卡尔工作室饰品系统篇
2013/04/25 DOTA
介绍Python中的一些高级编程技巧
2015/04/02 Python
Python中DJANGO简单测试实例
2015/05/11 Python
Python解惑之整数比较详解
2017/04/24 Python
Python cookbook(数据结构与算法)筛选及提取序列中元素的方法
2018/03/19 Python
python 将list转成字符串,中间用符号分隔的方法
2018/10/23 Python
对python numpy.array插入一行或一列的方法详解
2019/01/29 Python
俄罗斯美容和健康网上商店:Созвездие Красоты
2019/07/23 全球购物
为什么要有struct关键字
2012/05/08 面试题
SQL Server 2000数据库的文件有哪些,分别进行描述。
2015/11/09 面试题
中专三年学习的个人自我评价
2013/12/12 职场文书
校园元旦活动总结
2014/07/09 职场文书
民主生活会汇报材料
2014/12/15 职场文书
如何使用Maxwell实时同步mysql数据
2021/04/08 MySQL
你真的会用Mysql的explain吗
2022/03/31 MySQL