一 proxy模块处理请求的流程
① 流程图
- 说明: 这里'假定'nginx从client接收的是'http协议','转发给上游'的也是http协议
-
- 备注: 后续根据'处理'请求的流程,来讲解'相关指令'
- ++++++++++++++ "重点关注proxy_pass的三点" ++++++++++++++
-
- 1) dns'解析'
-
- 2) 涉及'path、query、uri'等
-
- 3) proxy_pass 中attatch_url是否存在对于'uri转码'影响
① 基本解读
- 说明: proxy_pass是一个'动作'指令,'不会'被继承
-
- 备注: 常见'add_header'、'proxy_paas'、rewrite模块指令可以用在'if in location'中
② proxy_pass的形式 域名解析问题
- 重点: 理解'proxy_pass'的构成
-
- 1)"协议[http、https]"+"://"+"域名[ip]:端口"+"option[可选]的attach_url"
-
- 2)"协议[http、https]"+"://"+"upstream_id"+"[可选]的attach_url"
-
- 注意:变量可以用在'proxy_pass'组成的'任何'一部分
-
- ++++++++'proxy_pass的形式'++++++++
-
- 字面值ip、'域名'、'upstream_id'、'变量[表示域名]' -->四种方式设置'上游[源站]'地址
-
- 1)有'变量',先'预'编译,'reload|restart'不会报错,等'客户端的请求'来了再'handle处理'
-
- 特点: 必须使用nginx的'resolver指令'
-
- 方式1: '自定义域名变量'
-
- # 多个'dns_server' 需要使用'空格'分割
-
- resolver 114.114.114.114 8.8.8.8 valid=30s;
-
- # 通过set自定义变量
-
- set $target www.baidu.com;
-
- proxy_pass http://$target;
-
- 方式2: '客户端传递的http变量' --> "预定义变量"
-
- proxy_pass http://$http_target;
-
- 应用场景: '客户端'如何控制'代理服务器'转发的'后端'服务器 -->'请求头|查询参数'
-
- 安全: 涉及'正向代理出公网',要保证'$http_target'是白名单,只保证对'白名单'的ip开防火墙
-
- 方式3: 裸域名,但变量在'attach_url'中,也必须使用'resolver' --> "见下面的案例"
-
- 特性:服务'启动'的时候,'绕过域名检查';有'请求过来'的时候,需要'resolver'指令进行域名解析
- 2) 无'变量'则使用'os'的DNS解析能力
-
- 方式:常见的'裸域名'
-
- 3) 有'变量',但是也使用'os'的DNS解析能力
-
- 方式:使用'upstream_id',但'upstream_id'中使用'域名' --> "特殊"
说明: proxy_pass http://source1.wzj.com; '等价' 隐式创建上面的'upstream'
用源码分析proxy_pass、upstream、resolver
- 最佳实践: os的'/etc/resolv.conf'相关选项配置成和nginx的'resolver'的指令保持一致
-
- 最佳做法: 使用openresty 'resolver' 的'local=on'参数
- 思考: 如果proxy_pass的形式同时满足'upstream_id'和'域名',哪个优先级'高'? --> "前者"
-
- 测试方法:注释'upstream nginx.wzj.com'前后'观察'现象
-- 对比'实验'
- 1) nginx何时使用'os的/etc/resolv.conf'? 何时使用'nginx的resolver 配置指令'?
-
- 2) proxy_pass的值有'变量'
-
- [0]、常见:域名用'变量(动态域名解析)'代替,其它部分用'变量'同理
-
- 备注: 用变量表示'upstream_id'除外
-
- [1]、需要指定'resolver'指令 -->
-
- [2]、缺点:无法使用'upstream'模块的'健康检查、会话保持'等功能
-
- 3) proxy_pass'不使用'变量
-
- [1]、会使用os的'/etc/hosts或/etc/resolv.conf'进行解析
-
- [2]、如果'域名对应'多个'A'记录,会导致'负载不均衡',DNS单点故障 -> "解析结果成为常驻内存"
- +++++++++++++ "nginx关于dns的三种报错" +++++++++++++
-
- 归根结底: 用'谁'对域名进行解析
-
- 1) no resolver defined to resolve source.wzj.com --> reload不报错,'handle'时报错
-
- 2) host not found in upstream source.wzj.com --> reload报错,os'无法'解析dns
-
- 补充场景: 或'不存在'此upstream_id
-
- 3) source.wzj.com could not be resolved --> '定义resolver',不能解析域名
core模块提供resolver指令 upstream模块提供resolver指令 openresty 提供的resolver指令
④ attach_url
说明: 这里的'attach_url'指的是'proxy_pass中除了协议、域名、端口的'uri
(1)案例1
测试1: proxy_pass '不'携带 'attach_url'
结论: proxy_pass '不携带' attach_url,会将'client原始的url'转发给上游
(2)案例2
测试2: proxy_pass '携带attach_url',attach_url为'/'
- request_uri: '/ceshi/index.html'
-
- location 匹配 '/ceshi/',剩余'index.html' 添加到 'attach_url --> / ' 后面
-
- 后端收到的请求: '/index.html'
(3) 案例3
- +++++++++++ "解读" +++++++++++
-
- 1)request_uri: '/ceshi/hello.html'
-
- 2) location: '/ceshi/'
-
- 3) attatch_url: '/abc'
-
- 4) location匹配后,剩余的'hello.html'追加到proxy_pass的'attach_url'中
-
- --> '/abchello.html'
⑤ nginx无法确认attach_url 重点
- 1) 某些情况下,'无法确定'请求URI中'替换'的部分,需要用到'正则'表达式
-
- 2) rewrite、proxy_pass、break '结合'使用
(1)案例1
- 1)原来'错误'的理解
-
- 当'location'带有'~、~* [以~开头]'正则时,proxy_pass'不允许'有URI
-
- URI表现: 变量、文本、或'混合'的形式
-
- 2) '修证后'的理解
-
- 如果location使用正则表达式,proxy_pass中'不能指定[裸]path',除非proxy_pass中包含'变量'
-
- +++++++++ "以下是两个对比案例" +++++++++
-
- 重点'关注': location中指定"正则表达式"和proxy_pass配置的"attach_url中带变量"混合场景
如果'location'使用'正则表达式',proxy_pass中'不能'指定裸path,除非proxy_pass中包含'变量'
- ++++++++++++++ "扩展学习" ++++++++++++++
-
- location /abc/d {
- if ( $request_uri ~ /abc/d/(.+) ) {
- set $args $1;
- }
- proxy_pass https://backend/ef/$args;
- }
-
- ============'等价'方式============
-
- location ~ /abc/d/(.+) {
- proxy_pass https://backend/ef/$1;
- }
(2)案例2
- 1) rewrite通过'break'改变'uri',此时'proxy_pass'的'attach_url'被'ignored'忽略
-
- 场景:proxy_pas有'attach_url',但是又要将'原始请求'转发到'后端',使用'$request_uri'变量
-
- 2)使用proxy_pass中指定的域名加上'rewrite中指定的path路径'即为转发后的url
-
- 补充解读: 先'重定向',再'proxy_pass反向代理'
解读: rewrite指令是在'rewrite'阶段执行,break'标志位'标示这是'最终'的'资源路径'
(3) 案例3
- 1)当'attach_url'中携带'变量'
-
- 2) 会用'proxy_pass中解析后的uri'替换'原始uri',作为最终转发到后端的'uri'
-
- 注意: 与'案例1'的差异点
POST请求经过301重定向后会变成GET请求,并且会丢失请求参数,印证报错"请求的body丢失"
- 1) proxy_paas 想'改变url'
-
- [1]、通过'attach_url'+'localtion',这里假定'没有'rewrite
-
- 1、'没有'attach_url
-
- 特点:将客户端'发来的 path 部分'拼接到proxy_paas中,然后发送到'上游'
-
- 2、attach_url为'裸path'
-
- 1、nginx 会把'解码过的'由客户端发来的 URI 里的 path 部分;
-
- 2、'去掉'和当前 location 的'公共前缀',再进行'编码',按 'NGX_ESCAPE_URI' 来操作;
-
- 3、然后和 proxy_pass 指令指定 的 'path 拼接',发送到上游;
-
- 3、attach_url'带变量' --> 将解析变量,然后直接将'解析后的 URI' 发送到上游
-
- 说明: 带attach_url,涉及'url编码','decode解码后'传递给后端服务
-
- [2]、rewrite break的方式 --> 也可以'改变最终uri'或'通过?改变查询参数'或'传递#锚点'