难道只有我懂Nginx/OpenResty详解,Nginx的rewrite模块指令?
nanshan 2024-10-26 11:14 11 浏览 0 评论
Nginx的rewrite模块指令
Nginx的rewrite模块即ngx_http_rewrite_module标准模块,主要功能是重写请求URI,也是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后根据指令参数或者发起内部跳转再一次进行location匹配,或者直接进行30x重定向返回客户端。
rewrite模块的指令就是一门微型的编程语言,包含set、rewrite、break、if、return等一系列指令。
set指令
set指令是由ngx_http_rewrite_module标准模块提供的,用于向变量存放值。在Nginx配置文件中,变量只能存放一种类型的值,因为只存在一种类型的值,那就是字符串。
set指令的配置项格式如下:
set $variable value;
注意:在Nginx配置文件中,变量定义和使用都要以$开头。Nginx变量名前面有一个$符号,这是记法上的要求。所有的Nginx变量在引用时必须带上$前缀。另外,Nginx变量不能与Nginx服务器预设的全局变量同名。比如,我们的nginx.conf文件中有下面这一行配置:
set $a "hello world";
上面的语句中,set配置指令对变量$a进行了赋值操作,把字符串hello world赋给了它。也可以直接把变量嵌入字符串常量中以构造出新的字符串:
set $a "foo";
set $b "$a, $a";
这个例子通过前面定义的变量$a的值来构造变量$b的值,于是这两条指令顺序执行完之后,$a的值是"foo",而$b的值则是"foo,foo"。把变量嵌入字符串常量中以构造出新的字符串,这种技术在Linux Shell脚本中常常用到,并且被称为“变量插值”(VariableInterpolation)。
set指令不仅有赋值的功能,还有创建Nginx变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,若$a这个变量尚未创建,则set指令会自动创建$a这个用户变量。
Nginx变量一旦创建,其变量名的可见范围就是整个Nginx配置,甚至可以跨越不同虚拟主机的server配置块。但是,对于每个请求,所有变量都有一份独立的副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。Nginx变量的生命期是不可能跨越请求边界的。
rewrite指令
rewrite指令是由ngx_http_rewrite_module标准模块提供的,主要功能是改写请求URI。rewrite指令的格式如下:
rewrite regrex replacement [flag];
如果regrex匹配URI,URI就会被替换成replacement的计算结果,replacement一般是一个“变量插值”表达式,其计算之后的字符串就是新的URI。
下面的例子有两个重新配置项,具体如下:
location /download/ {
rewrite ^/download/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 last;
rewrite ^/download/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb last;
return 404;
}
location /view {
echo "uri: $uri ";
}
在浏览器中请求http://crazydemo.com/download/1/video/10,地址发生了重写,并且发生了location的跳转,结果如图7-17所示。
在这个演示例子中,replacement中的占位变量$1、$2的值是指令参数regrex正则表达式从原始URI中匹配出来的子字符串,也叫正则捕获组,编号从1开始。
rewrite指令可以使用的上下文为:server、location、if inlocation。
如果rewrite同一个上下文中有多个这样的rewrite重新指令,匹配就会依照rewrite指令出现的顺序先后依次进行下去,匹配成功之后并不会终止,而是继续往下匹配,直到返回最后一个匹配的为止。如果想要中途中止,不再继续往下匹配,可以使用第3个指令参数flag。flag参数的值有last、break、redirect、permanent。
如果flag参数使用last值,并且匹配成功,那么停止处理任何rewrite相关的指令,立即用计算后的新URI开始下一轮的location匹配和跳转。前面的例子使用的就是last参数值。
如果flag参数使用break值,就如同break指令的字面意思一样,停止处理任何rewrite的相关指令,但是不进行location跳转。
将上面的rewrite例子中的last参数值改成break,代码如下:
location /view {
echo " view : $uri ";
}
location /download_break/ {
rewrite ^/download_break/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 break;
rewrite ^/download_break/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb break;
echo " download_break new uri : $uri ";
}
在浏览器中请求http://crazydemo.com/download_break/1/video/10,地址发生了重写,但是location并没有跳转,而是直接结束了,结果如图7-18所示。
在location上下文中,last和break是有区别的:last其实就相当于一个新的URL,Nginx进行了一次新的location匹配,通过last获得一个可以转到其他location配置中处理的机会(内部的重定向);而break在一个location中将原来的URL(包括URI和args)改写之后,再继续进行后面的处理,这个重写之后的请求始终都是在同一个location上下文中,并没有发生内部跳转。
这里要注意:last和break的区别仅仅发生在location上下文中;如果发生在server上下文,那么last和break的作用是一样的。
还要注意:在location上下文中的rewrite指令使用last指令参数会再次以新的URI重新发起内部重定向,再次进行location匹配,而新的URI极有可能和旧的URI一样再次匹配到相同的目标location中,这样死循环就发生了。当循环到第10次时,Nginx会终止这样无意义的循环并返回500错误。这一点需要特别注意。
如果rewrite指令使用的flag参数的值是permanent,就表示进行外部重定向,也就是在客户端进行重定向。此时,服务器将新URI地址返回给客户端浏览器,并且返回301(永久重定向的响应码)给客户端。客户端将使用新的重定向地址再发起一次远程请求。
永久重定向permanent的使用示例如下:
#rewrite指令permanent参数演示
location /download_permanent/ {
rewrite ^/download_permanent/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 permanent;
rewrite ^/download_permanent/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb permanent; return 404;
}
在浏览器中请求http://crazydemo.com/download_permanent/1/video/10,输出的结果如图7-19所示。
从以上结果可以看出,永久重定向有两个比较大的特点:
(1)浏览器的地址栏地址变成了重定向地址
http://crazydemo.com/view/1/mp3/10.mp3。
(2)从Fiddler抓包工具可以看到,第一个请求地址的响应状态码为301,如图7-20所示。
外部重定向与内部重定向是有本质区别的。从数量上说,外部重定向有两次请求,内部重定向只有一次请求。通过上面的几个示例,大家应该体会得相当深刻了。
如果rewrite指令使用的flag参数的值是redirect,就表示进行外部重定向,表现的行为与permanent参数值完全一样,不同的是返回302(临时重定向的响应码)给客户端。
有关redirect参数值的实例这里不进行演示,大家可自行下载和运行本文的源码并细细体会。
rewrite能够利用正则捕获组设置变量,作为实验,我们可以在Nginx的配置文件中加入这么一条location规则:
location /capture_demo {
rewrite ^/capture_demo/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 break;
rewrite ^/capture_demo/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb break;
捕获组
捕获组 echo " 捕获组1:$1;捕获组2:$2";
}
在浏览器中请求http://crazydemo.com/capture_demo/group1/video/group2,输出的结果如图7-21所示。
if条件指令
if条件指令配置项的格式如下:
if (condition) {...}
当if条件满足时,执行配置块中的配置指令。if的配置块相当于引入了一个新的上下文作用域。if条件指令适用于server和location两个上下文。
condition条件表达式可以用到一系列比较操作符,大致如下:
(1)==:相等。
(2)!=:不相等。
(3)~:区分字母大小写模式匹配。
(4)~*:不区分字母大小写模式匹配。
(5)还有其他几个专用比较符号,比如判断文件及目录是否存在的符号,等等。
下面是一个简单的演示程序,根据内置变量$http_user_agent的值判断客户端的类型,代码如下:
#if指令的演示程序
location /if_demo {
if ($http_user_agent ~*"Firefox") { #匹配Firefox浏览器
return 403;
}
匹配谷歌浏览器
if ($http_user_agent ~*"Chrome") { #匹配Chrome谷歌浏览器
return 301;
}
if ($http_user_agent ~*"iphone") { #匹配iPhone手机
return 302;
}
if ($http_user_agent ~*"android") { #匹配安卓手机
return 404;
}
return 405; #其他浏览器默认访问规则
}
在火狐浏览器中访问http://crazydemo.com/if_demo,结果如图7-22所示。
在谷歌浏览器中访问http://crazydemo.com/if_demo,结果如图7-23所示。
在演示代码中使用到了return指令,用于返回HTTP的状态码。
return指令会停止同一个作用域的剩余指令处理,并返回给客户端指定的响应码。
return指令可以用于server、location、if上下文中,执行阶段是rewrite阶段。其指令的格式如下:
#格式一:返回响应的状态码和提示文字,提示文字可选
return code [text];
#格式二:返回响应的重定向状态码(如301)和重定向URL
return code URL;
#格式三:返回响应的重定向URL,默认的返回状态码是临时重定向302
return URL;
add_header指令
response header一般是以key:value的形式,例如Content-Encoding:
gzip、Cache-Control:no-store,设置的命令如下:
add_header Cache-Control no-store
add_header Content-Encoding gzip
但是,有一个十分常用的response header为Content-Type,可以在它设置了类型的同时指定charset,例如text/html;charset=utf-8,由于其存在分号,而分号在配置文件中作为结束符,因此在配置时需要用引号把其引起来,配置如下:
add_header Content-Type 'text/html; charset=utf-8';
另外,由于没有单独设置charset的key,因此要设置响应的charset就需要使用Content-Type来指定charset。
使用AJAX进行跨域请求时,浏览器会向跨域资源的服务端发送一个OPTIONS请求,用于判断实际请求是否安全或者判断服务端是否允许跨域访问,这种请求也叫作预检请求。跨域访问的预检请求是浏览器自动发出的,用户程序往往不知情,如果不进行特别的配置,那么客户端发出一次请求,在服务端往往会收到两个请求;一个是预检请求;另一个是正式的请求。后端的服务器(PHP或者Tomcat)如果不经过特殊的过滤,那么很容易将OPTIONS预检请求当成正式的数据请求。
对于客户端而言,只有预检请求返回成功,客户端才开始正式请求。在实际的使用场景中,预检请求比较影响性能,用户往往会有两倍请求的感觉,所以一般会在Nginx代理服务端对预检请求进行提前拦截,同时对预检请求设置比较长时间的有效期。
upstream zuul {
#server 192.168.233.1:7799;
server "192.168.233.128:7799";
keepalive 1000;
}
server {
listen 80;
server_name nginx.server *.nginx.server;
default_type 'text/html';
charset utf-8;
#转发到上游服务器,但是 'OPTIONS' 请求直接返回空
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Max-Age 1728000;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Keep-Alive,User-Agent,X-Requested-With,\
If-Modified-Since,Cache-Control,Content-Type,token';
return 204;
}
proxy_pass http://zuul/ ;
}
}
配置Nginx,加入Access-Control-Max-Age请求头,用来指定本次预检请求的有效期,单位为秒。上面结果中的有效期是20天(1 728 000秒),即允许缓存该条回应1 728 000秒,在此期间客户端不用发出另一条预检请求。
指令的执行顺序
大多数Nginx新手都会频繁遇到这样一个困惑:当同一个location配置块使用了多个Nginx模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭。现在就来看这样一个令人困惑的例子:
location /sequence_demo_1 {
set $a foo;
echo $a;
set $a bar;
echo $a;
}
上面的代码先给变量$a赋值foo,随后输出,再给变量$a赋值bar,随后输出。如果这是一段Java代码,毫无疑问,最终的输出结果一定为“foo bar”。然而不幸的是,事实并非如此,在浏览器中访问http://crazydemo.com/sequence_demo_1,结果如图7-24所示。
为什么出现了这种不合常理的现象呢?
前面讲到,Nginx的请求处理阶段共有11个,分别是post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content以及log。其中3个比较常见的按照执行时的先后顺序依次是rewrite阶段、access阶段以及content阶段。
Nginx的配置指令一般只会注册并运行在其中的某一个处理阶段,比如set指令就是在rewrite阶段运行的,而echo指令只会在content阶段运行。在一次请求处理流程中,rewrite阶段总是在content阶段之前执行。因此,属于rewrite阶段的配置指令(示例中的set)总是会无条件地在content阶段的配置指令(示例中的echo)之前执行,即便是echo配置项出现在set配置项的前面。
上面例子中的指令按照请求处理阶段的先后次序排序,实际的执行次序如下:
location /sequence_demo_1 {
#rewrite阶段的配置指令,执行在前面
set $a foo;
set $a bar;
#content阶段的配置指令,执行在后面
echo $a;
echo $a;
}
所以,输出的结果就是bar bar了。
本文给大家讲解的内容是Nginx/OpenResty详解,Nginx的rewrite模块指令
- 下篇文章给大家讲解的是 Nginx/OpenResty详解,反向代理与负载均衡配置;
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
相关推荐
- 三种自建KMS激活系统自动激活windows方法
-
第一种:在windows服务器上搭建主要针对vol版本(win7、win10、win20xx、win2012等等)平台:我自己搭建的windows虚拟机,windows2016的操作系统软件:...
- 重装系统被收98元?避开Windows付费陷阱的实用指南
-
重装系统被收98元?避开Windows付费陷阱的实用指南有网友反映,在重装Windows系统后,屏幕突然弹出“激活系统需支付98元服务费”的提示,疑惑自己是不是遭遇了付费陷阱。事实上,微软官方的Wi...
- Windows Server2012远程桌面服务配置和授权激活
-
安装:注意:安装完毕之后需手动重启一下计算机配置终端服务管理工具---远程桌面服务---RD授权诊断程序,查看当前服务器有没有授权授权:运行—>gpedit.msc->计算机配置---管理...
- 新书速览|Windows Server 2022 系统与网站配置实战
-
讲述桌面体验、ServerCore/NanoServer,容器与云系统的配置1本书内容《WindowsServer2022系统与网站配置实战》秉持作者一贯理论兼具实践的写作风格,以新版的Wi...
- Windows激活全攻略:KMS神钥与专业工具的完美结合!
-
对于许多Windows用户来说,系统的激活是一个必经的过程。虽然Windows操作系统在未经激活的状态下也可以使用一段时间,但长期来看,未激活的系统会限制某些功能并频繁提示用户激活。以下是两种流行的激...
- 微软Win9全新激活技术曝光(微软系统激活有什么用)
-
2014-07-0905:46:00作者:徐日俄罗斯Wzor日前披露了更多关于Windows9的最新消息,据悉,Windows9将会在今年秋季亮相,其宣传口号是“想要开始按钮和开始菜单?如你所...
- 快速激活Windows 10/11:CMD命令详细教程
-
#记录我的2024#激活Windows操作系统是确保系统功能和安全更新正常运行的重要步骤。本文将为您分享如何使用命令提示符(CMD)在Windows10和Windows11上进行激活的详细步骤。...
- Wndows 2019 RDS应用发布部署(rds的安装和应用程序的发布)
-
安装前的准备1、需要提供服务器作为应用中心,应用中心的推荐配置如下表所示。规格建议1-10人11-20人21-50人51-100人100+人CPU4核8核16核内存8GB16GB32GB64GB系统盘...
- 解决 Windows 系统激活难题(如何解决windows激活问题)
-
今天,一位朋友给我说,他手头有三台电脑,均同时弹出系统未激活的提示。他对此毫无头绪,便急忙将电脑上出现的激活提示信息一股脑发给了我。我看到其中一台显示的是“Windows10企业版LTSC尚...
- 自建KMS激活服务器(自建kms激活服务器的风险)
-
自建KMS激活服务器Win10和office安装后,都需要激活才可以使用,一般可以输入购买的MAK激活码进行在线激活,也可以通过KMS激活,网上也有很多激活工具,但这些工具一般都含有病毒或木马程序,容...
- 30秒免费激活windows和office亲测有效!
-
“第三方工具有病毒?”“KMS服务器激活总失效?”今天给大家分享一个开源激活工具——MicrosoftActivationScripts(MAS),无需密钥、不装软件,30秒永久激活Window...
- 「操作系统」Windows 10 LTSC 2019 企业版C大集成更新版
-
Windows10LTSC企业版CHIANNET集成更新优化整合多镜像版,CHIANNET,是USBOS超级PE维护盘工具箱作者,长久以来一直默默的更新着,USBOSPE软件,电脑城装机及...
- 一文看懂Windows激活:自查方法+授权类型科普(Win7/Win10通用)
-
一、如何判断Windows是否永久激活?无论是Win7还是Win10,均可通过以下方法快速验证:命令提示符法(通用):按下Win+R,输入slmgr.vbs/xpr并按回车键运行即可查看是否...
- 部分Windows Server 2019/2022用户反馈无法运行微软Teams应用
-
IT之家7月2日消息,科技媒体borncity今天(7月2日)发布博文,报道称在多个WindowsServer版本上,MicrosoftTeams应用近期出现了运行故障。用...
- 这种Windows激活方式已有20年...(windows现在激活)
-
2006年微软正式发布WindowsVista,随之而来引入了一项新的激活机制「OEM激活」,这项机制在Vista和Win7上最为流行。其实WindowsServer自2008开始至2025版本一...
你 发表评论:
欢迎- 一周热门
-
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
NAS:DS video/DS file/DS photo等群晖移动端APP远程访问的教程
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
手机如何设置与显示准确时间的详细指南
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
一加手机与电脑互传文件的便捷方法FileDash
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
- 最近发表
-
- 三种自建KMS激活系统自动激活windows方法
- 重装系统被收98元?避开Windows付费陷阱的实用指南
- Windows Server2012远程桌面服务配置和授权激活
- 新书速览|Windows Server 2022 系统与网站配置实战
- Windows激活全攻略:KMS神钥与专业工具的完美结合!
- 微软Win9全新激活技术曝光(微软系统激活有什么用)
- 快速激活Windows 10/11:CMD命令详细教程
- Wndows 2019 RDS应用发布部署(rds的安装和应用程序的发布)
- 解决 Windows 系统激活难题(如何解决windows激活问题)
- 自建KMS激活服务器(自建kms激活服务器的风险)
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)