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 相关文章推荐
Nginx实现反向代理
Sep 20 Servers
win10安装配置nginx的过程
Mar 31 Servers
教你快速构建一个基于nginx的web集群项目
Nov 27 Servers
Nginx 反向代理解决跨域问题多种情况分析
Jan 18 Servers
详解使用内网穿透工具Ngrok代理本地服务
Mar 31 Servers
CentOS安装Nginx并部署vue
Apr 12 Servers
openstack云计算keystone组件工作介绍
Apr 20 Servers
利用Apache Common将java对象池化的问题
Jun 16 Servers
nginx之queue的具体使用
Jun 28 Servers
如何让你的Nginx支持分布式追踪详解
Jul 07 Servers
Apache自带的ab压力测试工具的实现
Jul 23 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
2006/12/23 PHP
特详细的PHPMYADMIN简明安装教程
2008/08/01 PHP
解析php通过cookies获取远程网页的指定代码
2013/06/25 PHP
php正则替换处理HTML页面的方法
2015/06/17 PHP
PHP微商城开源代码实例
2019/03/27 PHP
extjs 的权限问题 要求控制的对象是 菜单,按钮,URL
2010/03/09 Javascript
单独使用CKFinder选择图片的方法
2010/08/21 Javascript
GreyBox技术总结(转)
2010/11/23 Javascript
基于jquery的拖动布局插件
2011/11/25 Javascript
jquery的冒泡事件的阻止与允许(三种实现方法)
2013/02/01 Javascript
JavaScript计算字符串中每个字符出现次数的小例子
2013/07/02 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
AngularJS自定义服务与fliter的混合使用
2016/11/24 Javascript
WebStorm ES6 语法支持设置&babel使用及自动编译(详解)
2017/09/08 Javascript
Angular4 ElementRef的应用
2018/02/26 Javascript
基于Vue实现拖拽效果
2018/04/27 Javascript
详解在Vue中使用TypeScript的一些思考(实践)
2018/07/06 Javascript
使用vue根据状态添加列表数据和删除列表数据的实例
2018/09/29 Javascript
JS如何寻找数组中心索引过程解析
2020/06/01 Javascript
vue element el-transfer增加拖拽功能
2021/01/15 Vue.js
[09:37]2018DOTA2国际邀请赛寻真——不懈追梦的Team Serenity
2018/08/13 DOTA
python实现多线程采集的2个代码例子
2014/07/07 Python
python实现简单爬虫功能的示例
2016/10/24 Python
python3读取csv和xlsx文件的实例
2018/06/22 Python
Python自定义装饰器原理与用法实例分析
2018/07/16 Python
pymysql模块的使用(增删改查)详解
2019/09/09 Python
python在不同条件下的输入与输出
2020/02/13 Python
python GUI库图形界面开发之PyQt5多线程中信号与槽的详细使用方法与实例
2020/03/08 Python
构建高效的python requests长连接池详解
2020/05/02 Python
HTML5 source标签:媒介元素定义媒介资源
2018/01/29 HTML / CSS
英国家庭家具、照明和花园家具购物网站:Furniture123
2018/12/31 全球购物
体育学院毕业生自荐信
2013/11/03 职场文书
民事答辩状范本
2015/05/21 职场文书
2016年党员创先争优承诺书
2016/03/25 职场文书
css实现文章分割线样式的多种方法总结
2021/04/21 HTML / CSS
高并发下Redis如何保持数据一致性(避免读后写)
2022/03/18 Redis