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配置80端口访问8080及项目名地址方法解析
Mar 31 Servers
Nginx反向代理及负载均衡如何实现(基于linux)
Mar 31 Servers
Nginx解决403 forbidden的完整步骤
Apr 01 Servers
Nginx进程调度问题详解
Sep 25 Servers
Nginx图片服务器配置之后图片访问404的问题解决
Mar 21 Servers
nginx location 带斜杠【 / 】与不带的区别
Apr 13 Servers
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
May 11 Servers
聊聊配置 Nginx 访问与错误日志的问题
May 25 Servers
Nginx静态压缩和代码压缩提高访问速度详解
May 30 Servers
本地搭建minio文件服务器(使用bat脚本启动)的方法
Jul 15 Servers
django项目、vue项目部署云服务器的详细过程
Jul 23 Servers
教你使用Ubuntu搭建DNS服务器
Sep 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
基于文本的留言簿
2006/10/09 PHP
ajax缓存问题解决途径
2006/12/06 PHP
laravel自定义分页效果
2017/07/23 PHP
JavaScript 模仿vbs中的 DateAdd() 函数的代码
2007/08/13 Javascript
IE和Firefox下javascript的兼容写法小结
2008/12/10 Javascript
基于jquery的无刷新分页技术
2011/06/11 Javascript
jQuery多级弹出菜单插件ZoneMenu
2014/12/18 Javascript
js判断当前页面用什么浏览器打开的方法
2016/01/06 Javascript
Angular.js中用ng-repeat-start实现自定义显示
2016/10/18 Javascript
原生JS实现导航下拉菜单效果
2020/11/25 Javascript
详解JavaScript基础知识(JSON、Function对象、原型、引用类型)
2018/01/16 Javascript
webpack 插件html-webpack-plugin的具体使用
2018/04/09 Javascript
js实现贪吃蛇小游戏
2019/10/29 Javascript
浅谈vue生命周期共有几个阶段?分别是什么?
2020/08/07 Javascript
vue+iview使用树形控件的具体使用
2020/11/02 Javascript
[42:48]完美世界DOTA2联赛PWL S3 Magma vs INK ICE 第二场 12.11
2020/12/16 DOTA
简单讲解Python中的字符串与字符串的输入输出
2016/03/13 Python
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
2016/12/27 Python
Windows上安装tensorflow  详细教程(图文详解)
2020/02/04 Python
使用python3 实现插入数据到mysql
2020/03/02 Python
简单了解python关键字global nonlocal区别
2020/09/21 Python
html5 迷宫游戏(碰撞检测)实例一
2013/07/25 HTML / CSS
美国睫毛、眉毛精华液领导品牌:RevitaLash Cosmetics
2018/03/26 全球购物
某公司C#程序员面试题笔试题
2014/05/26 面试题
Weblogic和WebSphere不同特点
2012/05/09 面试题
家长给孩子的表扬信
2014/01/17 职场文书
销售主管竞聘书
2014/03/31 职场文书
4s店销售经理岗位职责
2014/07/19 职场文书
实习工作表现评语
2014/12/31 职场文书
英文慰问信
2015/02/14 职场文书
2015年预防青少年违法犯罪工作总结
2015/05/22 职场文书
Mybatis-plus在项目中的简单应用
2021/07/01 Java/Android
Python+Selenium实现读取网易邮箱验证码
2022/03/13 Python
纯CSS实现一个简单步骤条的示例代码
2022/07/15 HTML / CSS
详解SQL报错盲注
2022/07/23 SQL Server
前端框架ECharts dataset对数据可视化的高级管理
2022/12/24 Javascript