nginx(三十二)rewrite模块

一    官方rewrite模块

1)这个模块作用于'SERVER_REWRITE'和'REWRITE'阶段,前者的优先级'较高'

2)根据rewrite模块出现在'server{}'还是'location{}',判断属于'哪个'阶段

①   模块涉及的指令

②   基本简介

pcre下载地址

pcretest测试正则表达式

二   return指令细讲

①  return

说明: 首先'讲解'这个指令的原因是,我们经常拿来'做测试'使用

备忘录: 返回'文本(text)'的时候,经常忘记加'code' --> 易错: return 200 'ok'

影响重定向的几个指令

nginx 444 状态码  nginx自定义的状态码

444: nginx的444状态被服务器'直接断开'连接,'不再向客户端返回'消息,简单粗暴

307: 使用'源请求'使用的method,而且会携带'源请求的body'作为重定向请求的包体

②  小程序验证码

背景: '百度、微信等'小程序跳转'华为云、腾讯云、阿里云'时候,必须验证

说明: default_type 设置'text/plain',是'避免'浏览器下载

实际: 根据'txt'后缀会自动根据'mine.type'返回'对应的Content-Type

③  优先级问题

(1)执行阶段优先级

'动作类'指令:无法'合并'

(2)同一阶段同一模块不同指令的优先级

+++++++++  "对比实验"  +++++++++

同一阶段同一模块不同指令的优先级:按照在'配置文件'中出现的'先后'顺序

(3)returnerror_page优先级

说明: 默认'error_page'只拦截'静态',不拦截'动态(后端返回的)'的指定'错误'状态码

是否'补获'后端错误: 'proxy_intercept_errors'开关指令

1)error_page是'少有'的、集成到'http框架中'的指令,'它不归属'任何阶段

2)仅当可能'返回错误指令'时,才会'使用'到它

3)所有阶段'都可能'返回响应,例如access、preaccess、rewrite等等,'error_page'可能会补获

+++++++++  "对比实验"  +++++++++

说明: 'return code'的优先级比相同code 'error_page code' 优先级高

(4)returnecho指令优先级

场景: 这两个'经常'用来做临时'调试'

  

解读:echo指令在'content阶'段执行,而'return'总在content阶段'之前'

④  常用案例

需求1: http'跳转'到https

server {
        listen 80;
        server_name www.wzj.com;
        return 301 https://$http_host$request_uri;
}

+++++++++++++++ "分割线"  +++++++++++++++

需求2:临时'调试'

return 200 $name $request_uri;


default_type application/json;
return 200  '{"name":"aming","id":"100"}';  # 返回json的形式

+++++++++++++++ "分割线"  +++++++++++++++

需求3:请求后缀'过滤'

location ~ .*\.(sh|bash)?$ {
   return 403;
   # deny all;
}

+++++++++++++++ "分割线"  +++++++++++++++

需求4:网站被'黑'了,凡是在'百度点击到本网站'的请求,全部都跳转到了一个'赌博'网站

if ($http_referer ~ 'baidu.com') {
    return 200 
"<html><script>window.location.href='//$host$request_uri';</script></html>";
}

三  rewrite指令细讲

①  rewrite

[1]、在一个 URL 请求中,rewrite 如果'匹配到' regex,那么 URL 就会'替换'成 replacement

[2]、如果'不考虑'flag,匹配规则'多个rewrite'是'顺序执行',即使匹配到了,仍然'会继续'匹配下去

[3]、如果 replacement 包含 "http://", "https://", or "$scheme"

  --> 那么匹配会'立即终止',并直接'重定向地址'给客户端

++++++++++ 'rewrite'哪些是重定向,哪些是'内部'转发  ++++++++++

1、涉及'https'、'http'、'$scheme' 都是'外部'重定向

   https|http|$scheme 这三种,默认是'redirect(302)',可以自己指定'permanent(301)'

   特点:一旦匹配上,立即终止'处理','直接返回'给客户端301、302,'不再进行'find_location阶段

   细节:客户端的'地址栏'会发生变化 

   原因:浏览器根据'301、302'的状态码+'Location'响应头再发一次请求

curl -Lkv 查看详细'交互'过程

2、如果'replacement'不是上述的,或者'不是'返回给客户端'301、302'响应状态码,则是'内部'跳转

 ②  案例讲解

(1)案例1  重定向

+++++++++ '补充' +++++++++

1)一旦'重定'向了,该'location 块'中后续的其它'rewrite脚本指令集'不再执行

2)细节点: 'add_header'还是会被执行

(2)案例2  break

体会: 'break'标志位的作用 -->只是'跳过当前'的rewrite阶段,并执行'本请求后续'的执行阶段

说明: location中包含'rewrite'模块多个'脚本指令的set集合'

++++++++++  "对比实验"  ++++++++++

 

(3)  nginx rewrite 中last break flag区别

++++++++++++++++++"假定rewrite在location中"++++++++++++++++++

[1].  last 和 break一样 它们都会'终止'此 location 中'其它rewrite模块指令'的执行

[2].  但是 last 立即发起'新一轮'的 location 匹配 而 break 则'不会'

补充: 'break'跳过'当前的rewrite'阶段,并执行本请求'输出'阶段

++++++++++++++++++++++++"分割线"++++++++++++++++++++++++
​
[1].  flag 参数'如果'是 'redirect' 或 'permanent',立刻'中止规则匹配',进行 '3xx' 跳转

[2].  如果在 location 中配置 'flag 是 last',立刻'跳出本 location' 的匹配

 -->同时会顺序'继续搜寻其他' location 的匹配,如果还'没匹配'到,还会继续'搜寻本' location

[3].  而 break '跳出本' location 后就'不会再匹配'其它 location 了

案例汇总 

1. 如果'rewrite'同一个上下文'有多个'这样的规则:无'https、http、$scheme',也无'flag'标识

2. 匹配会按照'rewrite'指令出现的'先后'顺序依次进行,匹配到一个后'不会终止';

   --> 而是'继续往下'匹配,直到返回'最后一个匹配上'的为止

+++++++++++++++++"分割线1"+++++++++++++++++

+++++++++++++++++"分割线2"+++++++++++++++++

+++++++++++++++++"分割线3"+++++++++++++++++

请求: http//rewrite.wzj.com/break/xx

输出: 'break page'

涉及: static和echo 模块'优先'级;root指令属于'static'模块

分析: 

  1. break是'跳过当前请求'的rewrite阶段,并'继续执行本请求'的'其他'阶段

  2. 很明显,对于/break 对应的'content阶段'的输出为 echo "break page"

  3. content阶段,可以简单理解为'产生数据输出的阶段'

  4. echo指令也是'运行在content阶段',一般情况下content阶段只能'对应一个'输出指令,如同一个location'配置两个echo',最终只会有一个echo指令被执行

  5. 当然如果你把'/break/'里的'echo 指令注释',然后再次访问/break/xx会'报404','static'模块起作用

  6. 虽然/break/xx'被重定向'到/test/xx,但是break指令'不会重新开启一个新的请求'继续匹配,所以nginx是'不会匹配到下面'的/test/这个location

  7. 在echo指令'被注释'的情况下,/break/ 这location里'只能执行'nginx'默认'的content指令,即'尝试找/test/xx这个html页面'并输出起内容,事实上,这个页面'不存在',所以会报404的错误

++++++++++++++  "分割线"  ++++++++++++++

请求: http//rewrite.wzj.com/last/xx

输出: 'test page'

分析: 

  1. last与break最大的'不同'是,last会'重新发起'一个新请求,并'重新匹配'location

  2. 所以对于/last,重新匹配请求以后'会匹配到/test/',所以最终'对应的content阶段'的输出是test page;

echo模块源码安装 

(4) 死循环场景

(5)查询参数

1. rewrite /a.html /new permanent          -->重定向'带原始参数'的地址

2. rewrite /a.html /new? permanent         -->重定向'不带'参数

3. rewrite /a.html /new?age=18 permanent   -->重定向'追加'查询参数

4. rewrite /a.html /new?id=$arg_id&name=$arg_name? permanent 重定向'带指定'参数

说明: '4'实质是'自定义查询参数'

return, rewrite, and try_files对比 辅助参考

各种奇怪的rewrite需求

问题引入: rewrite'301重定向'导致'查询参数重复'

"根因探讨": '$request_uri' 比'$uri'多了查询参数,rewrite默认就带'查询'参数,导致'重复'

++++++++++++++++++++ "以下三种等价解决策略" ++++++++++++++++++++

1) rewrite ^ https://ceshi2.wzj.com$request_uri?            --> "推荐"

  说明: 通过'?'改变'rewrite'查询参数的'默认'行为

2) rewrite ^ https://ceshi2.wzj.com$uri

  说明: 'rewrite'默认自动携带'查询参数'

3) rewrite ^(?<capture>.*)$ https://ceshi2.wzj.com$capture  --> "常见"

补充1: rewrite会导致html5的锚点或vue的hash路由模式下'#'数据丢失,因为'#'属于客户端数据

补充2: rewrite之后可以进行'#'透传;eg: rewrite ^ https://ceshi2.wzj.com$uri#first

③  rewrite的应用场景

④  rewrite使用正则的注意事项

注意1: 正则中使用 "}" or ";" ,必须使'(用单|双)'引号,因为'}、;'在nginx.conf有'特殊'含义

注意2: url如果含有' 空格',推荐使用使'(用单|双)'引号

   break指令细讲

①  break

疑惑点: 结束'该作用域'下剩余的指令,还是'只是该rewrite模块的'指令?

(1)配置demo

( 2)不带参数请求

(3)带参数请求 

由于URL中'&、&'不转义,curl请求最好加上'单引号',如果想使用'shell变量'则使用"双引号"
​
遗留:带参数同时配置中的'break'关闭看看效果

效果:整个请求就'被终止'了,后续的指令都'不'执行了,直接返回'404'

nginx的11个阶段

五   rewrite_log指令细讲

①  rewrite_log 

error.log开启'notice'级别,默认是'error'

六  if指令细讲

①  if

遗留: 简单记住在if里'只有rewrite的模块指令'是'安全'的
if指令'掌握'两个点:'自定义[set]'和'内置(模块提供)'变量和'正则'形式

掌握:if (condition) {} 中'condition'的场景

②  if 的 and else or 等价用法

++++++++++++++ '官方'案例  ++++++++++++++

$request_filename:当前'连接请求'的文件路径,由'root'或'alias指令'与URI请求生成

相关案例参考 

if ( $http_cookie ~* "name=wzj")   -->cookie'数据太大',优点不明显

if (remotr_addr ~* ^172\.25\.2\.*) -->限定'部分ip'访问

++++++++++++  server块中  ++++++++++++ 
 
if ($request_uri ~ /vnc/include/(.+)) {
    set $parms $1;
    # 体会这个'含义',个人感觉是终止'server中执行rewrite的'阶段
    break;
}

location /vnc {
    proxy_pass http://www.wzj.com/$parms
}

高级:nginx 剔除 $args 变量中任意指定参数

七   set指令细讲

①  set

细节点: 除了'变量$args'可以被'修改'以外,其'对应的子变量值'都只是'只读',而'不能'进行修改

补充: rewrite正则、set'自定义'、map、location正则、server_name -->可以'产生变量'

 作用域问题

②  set细节补充

++++++++  "set细节补充"  ++++++++

 1) 两个含义:'创建'变量,给变量'赋值',但是在'不同的阶段'

 2) 创建变量是在'加载'配置的时候 --> "reload|restart"是否报错

 3) 赋值变量是当'请求处理上下'文需要时'触发'

    eg: proxy_pass http://http_target ,用户在请求的时候没有传递'target'请求头则报错

 4) 直接调用一个'未被创建'的变量,会导致配置'无法'启动

 5) '变量名'是整个配置文件可见,但'变量的值'是基于'每个独立HTTP请求'的上下文

③  set变量作用域

1) 变量名是'整个配置文件'可见,但'变量的值'是基于每个独立请求的上下文

解读:变量是'全局'的

2) rewrite导致nginx'内部location跳转'情形下,此时请求还属于同一个请求,因此变量值是不变的

3) 同一个上下文,'多次set同一个变量',使用配置中最后一个set值

细节: rewrite模块return有'额外影响','什么'影响?

④   uninitialized_variable_warn

set 与 变量  set变量与子请求

八   高级正则

①  普通补获

捕获 (exp) :匹配exp,并捕获文本到'自动命名$1、$2、...$9'的组里 --> "常见"

+++++++++++ 'http跳转到https' +++++++++++

server {
    listen 80;
    server_name www.wzj.com ;
    rewrite ^(.*) http://www.wzj.com$1 permanent;
}

②  命名捕获

(?<name>exp):匹配exp,并'捕获文本'到名称为'name的组'里,也可以写成(?'name'exp)

说明:能'看懂'即可

  

③   非补获

​1.  语法:(?:pattern)

2.  解读:'非获取匹配','匹配'pattern但'不获取'匹配结果,'不进行存储'供以后使用

3.  这在使用或字符"(|)"来组合一个'模式'的'各个部分'是很有用

4.  例如:'industr(?:y|ies)'就是一个比'industry|industries'更简略的表达式

++++++++++ "案例讲解"  ++++++++++

if ($uri ~* \.(?:html|css|js|json)$){
      proxy_pass http://static/wzj.com
}

+++++++++ nginx自行对"/"处理 +++++++++

~* ^\/wzj\/(.+?\.(?:html|css|js))$   

说明:'/'不需要跟'shell'正则一样转义,nginx会'自行'处理

.*、.*?、.+?的含义

④  零宽度断言 

shell常用正则表达式

四个'非捕获组'用于匹配pattern'或者'不匹配pattern位置'之前'或'之后'的内容,匹配的结果'不包括'pattern

补充:(?#comment),这种类型的分组'不对'正则表达式的处理产生任何影响,用于'提供注释'让人阅读

 1)案例一

location ~* (?!.*/wzj/favicon).*(\.ico)$ {
    rewrite ^(.*) http://rewrite.wzj.com/static/wzj/favicon/favicon.ico permanent;
    # 备注:rewrite 'https://' --> 所以下面'return 301'不会执行
    return 301;
}

[1].  $request_uri 是'待匹配'的字符串

http://rewrite.wzj.com'/aa/bb/cc.ico'

http://rewrite.wzj.com'/wzj/favicon/favicon.ico'

http://rewrite.wzj.com'/wzj/favicon/favicon.txt'

[2].  (?!.*/wzj/favicon).*(\.ico)$ 是'正则模式'

遗留点:'回溯'的过程?

⑤  贪婪非贪婪模式

浅谈nginx反向代理中神奇的斜线  整理的案例

九   相关参考

break和last理解

rewrite官方的一些案例

websocket官方配置

internal 指令限制访问图片资源文件

nginx internal 语法 – SRE笔记

重写与重定向的关系和配置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值