06 nginx 处理转发其他域的处理 以及 proxy_redirect
前言
容器端口映射导致 302 存在问题 以及 nginx 对于 302 的 Location 的重写
中描述了如果 上游服务 sendRedirect 到所在域的其他服务之后, 来到 nginx 这一层, nginx 会将这个转发的服务更新为 nginx 所在的域
那么 假设上游服务 sendRedirect 到其他域的服务呢 ?
另外 就是在 探究这个问题的时候, 使用了一下 proxy_redirect, 这个 proxy_redirect 又是如何处理的呢?
以下截图, 调试基于 nginx-1.18.0
测试用例
location ^~ /api/ {root html; index index.html index.htm;proxy_pass http://localhost:8080/;}
sendRedirect 的服务, 是部署在 8080 端口上面
通过 nginx 访问发现出现 302, 跳转的域是 给定的目标域, nginx 没有重写
nginx 对于其他非上游域的服务的302的处理
location 的重写模块这里有一个对于域的判断, 如果 不是当前域直接 DECLINED, 不走后面的 rewrite 的处理
另外还有一个细节是 这个流程的 location 还是存放在 request 的 header 列表, 没有写到 request.headers_out.location 里面
响应的 location 和 proxy_pass 的 域不一致, 直接走 DECLINED
Breakpoint 1, ngx_http_proxy_rewrite_complex_handler (r=0x7f98e2000a50, h=0x7f98e2001000, prefix=0, len=54, pr=0x7f98e0806ac0)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) print pattern
$1 = {len = 22, data = 0x7f98e0803b5b "http://localhost:8080/"}
(gdb) print h->value
$2 = {len = 54, data = 0x7f98e2002859 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
(gdb) list
2625
2626 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2627 return NGX_ERROR;
2628 }
2629
2630 if (pattern.len > len
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2632 pattern.len) != 0)
2633 {
2634 return NGX_DECLINED;
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2630 if (pattern.len > len
(gdb) next
2634 return NGX_DECLINED;
proxy_redirect
增加 proxy_redirect 的配置如下
location ^~ /api/ {root html; index index.html index.htm;proxy_pass http://localhost:8080/;proxy_redirect 80 83;proxy_redirect http://localhost http://127.0.0.1;}
来到 ngx_http_proxy_rewrite_redirect 的循环处理
可以看到 这里配置到的两个 proxy_redirect 分别为 80 -> 83, http://localhost -> http://127.0.0.1
响应的 location 为 http://localhost:8083/HelloWorld/listFormWithoutHeader
使用 80 -> 83 的配置的时候, 发现 location 不以 80 开头, 放弃处理
使用 http://localhost -> http://127.0.0.1 配置的时候, 执行了替换处理, 更新之后的 location 为 http://127.0.0.1:8083/HelloWorld/listFormWithoutHeader
Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) bt
#0 ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)at src/http/modules/ngx_http_proxy_module.c:2630
#1 0x000000010aacb893 in ngx_http_proxy_rewrite_redirect (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0)at src/http/modules/ngx_http_proxy_module.c:2524
#2 0x000000010aa894ed in ngx_http_upstream_rewrite_location (r=0x7fd48a814050, h=0x7fd48a82ee70, offset=0)at src/http/ngx_http_upstream.c:5100
#3 0x000000010aa8d9bd in ngx_http_upstream_process_headers (r=0x7fd48a814050, u=0x7fd48a82e5e0) at src/http/ngx_http_upstream.c:2806
#4 0x000000010aa8ede7 in ngx_http_upstream_process_header (r=0x7fd48a814050, u=0x7fd48a82e5e0) at src/http/ngx_http_upstream.c:2432
#5 0x000000010aa8e7e5 in ngx_http_upstream_handler (ev=0x10ac1f208)at src/http/ngx_http_upstream.c:1286
#6 0x000000010aa57c10 in ngx_kqueue_process_events (cycle=0x7fd48a80c050, timer=13648, flags=1) at src/event/modules/ngx_kqueue_module.c:669
#7 0x000000010aa479f6 in ngx_process_events_and_timers (cycle=0x7fd48a80c050)at src/event/ngx_event.c:247
#8 0x000000010aa55ac5 in ngx_worker_process_cycle (cycle=0x7fd48a80c050, data=0x0) at src/os/unix/ngx_process_cycle.c:750
#9 0x000000010aa52cfa in ngx_spawn_process (cycle=0x7fd48a80c050, proc=0x10aa55a10 <ngx_worker_process_cycle>, data=0x0, name=0x10ab1da1e "worker process", respawn=-3)at src/os/unix/ngx_process.c:199
#10 0x000000010aa54be7 in ngx_start_worker_processes (cycle=0x7fd48a80c050, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:359
#11 0x000000010aa54558 in ngx_master_process_cycle (cycle=0x7fd48a80c050)at src/os/unix/ngx_process_cycle.c:131
#12 0x000000010aa0c8ba in main (argc=3, argv=0x7ffee51f4548)at src/core/nginx.c:382
(gdb) frame 1
#1 0x000000010aacb893 in ngx_http_proxy_rewrite_redirect (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0)at src/http/modules/ngx_http_proxy_module.c:2524
2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
(gdb) print pr[0]
$3 = {handler = 0x10aac8a80 <ngx_http_proxy_rewrite_complex_handler>, pattern = {complex = {value = {len = 2, data = 0x7fd48a808fef "80"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x2}, replacement = {value = {len = 2, data = 0x7fd48a808ff2 "83"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
(gdb) print pr[1]
$4 = {handler = 0x10aac8a80 <ngx_http_proxy_rewrite_complex_handler>, pattern = {complex = {value = {len = 16, data = 0x7fd48a809097 "http://localhost"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x10}, replacement = {value = {len = 16, data = 0x7fd48a8090a8 "http://127.0.0.1"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
(gdb) print plcf->redirects->nelts
$5 = 2
(gdb) print h->value
$6 = {len = 54, data = 0x7fd48a82f059 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
(gdb) frame0
Undefined command: "frame0". Try "help".
(gdb) frame 0
#0 ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2630 if (pattern.len > len
(gdb) next
2634 return NGX_DECLINED;
(gdb) next
2642 }
(gdb) print pattern
$7 = {len = 2, data = 0x7fd48a808fef "80"}
(gdb) c
Continuing.Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050, h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a809128)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) print pattern
$8 = {len = 16, data = 0x7fd48a809097 "http://localhost"}
(gdb) print h->value
$9 = {len = 54, data = 0x7fd48a82f059 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
(gdb) next
2632 pattern.len) != 0)
(gdb) next
2630 if (pattern.len > len
(gdb) next
2637 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
(gdb) next
2641 return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
(gdb) next
2642 }
(gdb) print h->value
$10 = {len = 54, data = 0x7fd48a82f059 "http://127.0.0.1:8083/HelloWorld/listFormWithoutHeader"}
如果 proxy_pass 携带的有 uri, 并且没有配置 proxy_redirect
可以参见 容器端口映射导致 302 存在问题 以及 nginx 对于 302 的 Location 的重写
的场景
是可以看到 nginx 默认增加了一个 "http://localhost:8080/" -> "/api/" 的配置来处理, nginx 拿到 Location 响应头之后重写为相对路径
我们可以看一下
更新配置为如下
因为携带有 uri, 如果是上游本域的 302 需要将 上游本域信息更新为当前域, 因此有一个 "http://localhost:8080/" -> "/api/" 的替换操作
location ^~ /api/ {root html; index index.html index.htm;proxy_pass http://localhost:8080/;}
可以看到 确实是存在一条 "http://localhost:8080/" -> "/api/" 的替换操作
Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fec8a800450, h=0x7fec8a800a00, prefix=0, len=54, pr=0x7fec89001ec0)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) frame 1
#1 0x0000000100d2d893 in ngx_http_proxy_rewrite_redirect (r=0x7fec8a800450, h=0x7fec8a800a00, prefix=0)at src/http/modules/ngx_http_proxy_module.c:2524
2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
(gdb) print pr[0]
$11 = {handler = 0x100d2aa80 <ngx_http_proxy_rewrite_complex_handler>, pattern = {complex = {value = {len = 22, data = 0x7fec88008f5b "http://localhost:8080/"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x16}, replacement = {value = {len = 5, data = 0x7fec88007a94 "/api/"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
(gdb) print plcf->redirects->nelts
$12 = 1
这个替换的配置来自于
proxy_pass 带 uri, "/api/" -> "http://10.60.50.16:8081/"
proxy_pass 不带 uri, "/" -> "http://10.60.50.16:8081/"
如果手动添加了一条 proxy_redirect 那么默认的这个替换还存在吗?
配置文件如下, 增加了一条无用的 proxy_redirect
location ^~ /api/ {root html; index index.html index.htm;proxy_pass http://localhost:8080/;proxy_redirect 80 83;}
可以发现 上游服务响应的是上游服务所在的域的地址, 然后 nginx 拿到该地址之后 没有更新域为当前域
因为 已经存在 proxy_redirect, 没有添加 "http://localhost:8080/" -> "/api/" 的替换操作
拿到运行时的数据信息, 可以看到没有 "http://localhost:8080/" -> "/api/" 的替换操作
Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7ffd25000a50, h=0x7ffd25001000, prefix=0, len=54, pr=0x7ffd2400f820)at src/http/modules/ngx_http_proxy_module.c:2630
2630 if (pattern.len > len
(gdb) frame 1
#1 0x0000000107375893 in ngx_http_proxy_rewrite_redirect (r=0x7ffd25000a50, h=0x7ffd25001000, prefix=0)at src/http/modules/ngx_http_proxy_module.c:2524
2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
(gdb) print plcf->redirects->nelts
$13 = 1
(gdb) print pr[0]
$14 = {handler = 0x107372a80 <ngx_http_proxy_rewrite_complex_handler>, pattern = {complex = {value = {len = 2, data = 0x7ffd2400f7ef "80"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x2}, replacement = {value = {len = 2, data = 0x7ffd2400f7f2 "83"}, flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
(gdb)
关于 proxy_direct default
配置如下 proxy_redirect default;
运行时拿到的 替换配置如下 "/api/" -> "http://localhost:8080/"
这个和 “如果 proxy_pass 携带的有 uri, 并且没有配置 proxy_redirect” 创建的替换配置一样
proxy_pass 带 uri, "/api/" -> "http://10.60.50.16:8081/"
proxy_pass 不带 uri, "/" -> "http://10.60.50.16:8081/"
完
06 nginx 处理转发其他域的处理 以及 proxy_redirect相关推荐
- 跨域问题解决方案--Nginx代理转发
文章目录 问题描述 解决方案 问题描述 有这么一个html页面,具体代码如下: Nginx_CORS.html <!DOCTYPE html> <html lang="en ...
- 通过 Nginx 代理转发配置实现跨域(API 代理转发)
通过 Nginx 代理转发配置实现跨域(API 代理转发) 阅读 2285 收藏 119 2017-04-08 原文链接:www.thinktxt.com 1元视频体验视频通话10000分钟cloud ...
- vue反向代理解决跨域及部署nginx端口转发解决跨域
1. 前言 本文是为了解决vue反向代理解决跨域及部署服务器nginx端口转发解决跨域,因为踩了不少的坑,百度了很多,也试了太多的方法,最终得以解决,所以记录一下,希望遇到同样问题的友友们可以高效的解 ...
- nginx 代理解决跨域问题
前言 可能在某些时候我们的前端项目需要访问一些外部的接口,比如Apollo等,而直接使用axios发送请求的话,会报跨域的错误,具体什么是跨域这里就不啰嗦了,如下图. 这个接口地址当然是正确的,可以放 ...
- Nginx配置 转发URL中包含特殊字符
Nginx经常被用来作为代理服务器,可以有效的避免跨域问题. 老项目需要对接一个新的服务,但是存在跨域问题,然后就配置了一个代理 可是突然在某天,新接口出现了异常.接口报了400错误. # 转发 lo ...
- Nginx配置cros跨域以及遇到401响应的问题
nginx配置cros跨域以及遇到401.500响应的问题 这是我Nginx的server配置: server {listen 80;server_name DataAnalysis;location ...
- Nginx 解决WebApi跨域二次请求以及Vue单页面问题
Nginx 解决WebApi跨域二次请求以及Vue单页面问题 参考文章: (1)Nginx 解决WebApi跨域二次请求以及Vue单页面问题 (2)https://www.cnblogs.com/ji ...
- Nginx 代理转发阿里云OSS上传的实现代码
这篇文章主要介绍了Nginx 代理转发阿里云OSS上传的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 前言 因为小程序上传需要https,服务器https用的是 ...
- Nginx 实现AJAX跨域请求
AJAX从一个域请求另一个域会有跨域的问题.那么如何在nginx上实现ajax跨域请求呢?要在nginx上启用跨域请求,需要添加add_header Access-Control*指令.如下所示: 1 ...
最新文章
- MapReduce——shuffle
- 优秀设计师必备:视觉传达设计与视觉思维
- 最高效的进(线)程间通信机制--eventfd
- mysql 字符串搜_mysql – 在表中搜索字符串的SQL查询?
- 怎么生成a类型的对象 java_Java工程师考试题(答案)
- grafana 安装- 曲线图展示每秒新增数据量
- case when then else_SQL 优化大神玩转 MySQL函数系列_case_when 的坑
- 12. nc/netcat 用法举例
- zuul业务检查相关模块
- python网易云_Python分析网易云音乐近5年热门歌单
- 利用中文维基百科训练词向量模型
- 计算机英特尔显卡在哪找,Win10英特尔显卡设置在哪里 英特尔核芯显卡控制面板六大功能详解...
- mysql触发器安全吗_猎八哥浅谈MYSQL触发器
- 恒生期货交易时间(恒生指数期货交割日期)
- Sonic-Pi 初体验
- Welcome to Pete Brown's 10rem.net
- 测试/开发程序员的思考,突破变得更强......
- python模型预测控制_【模型工具】耦合python和 SWMM的城市排水系统模型预测算法...
- VMware下CentOS7最小化安装及配置
- kalilinux链接蓝牙音响_Kali-Linux安驱动、使用Blueman连接蓝牙耳机