前言

容器端口映射导致 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相关推荐

  1. 跨域问题解决方案--Nginx代理转发

    文章目录 问题描述 解决方案 问题描述 有这么一个html页面,具体代码如下: Nginx_CORS.html <!DOCTYPE html> <html lang="en ...

  2. 通过 Nginx 代理转发配置实现跨域(API 代理转发)

    通过 Nginx 代理转发配置实现跨域(API 代理转发) 阅读 2285 收藏 119 2017-04-08 原文链接:www.thinktxt.com 1元视频体验视频通话10000分钟cloud ...

  3. vue反向代理解决跨域及部署nginx端口转发解决跨域

    1. 前言 本文是为了解决vue反向代理解决跨域及部署服务器nginx端口转发解决跨域,因为踩了不少的坑,百度了很多,也试了太多的方法,最终得以解决,所以记录一下,希望遇到同样问题的友友们可以高效的解 ...

  4. nginx 代理解决跨域问题

    前言 可能在某些时候我们的前端项目需要访问一些外部的接口,比如Apollo等,而直接使用axios发送请求的话,会报跨域的错误,具体什么是跨域这里就不啰嗦了,如下图. 这个接口地址当然是正确的,可以放 ...

  5. Nginx配置 转发URL中包含特殊字符

    Nginx经常被用来作为代理服务器,可以有效的避免跨域问题. 老项目需要对接一个新的服务,但是存在跨域问题,然后就配置了一个代理 可是突然在某天,新接口出现了异常.接口报了400错误. # 转发 lo ...

  6. Nginx配置cros跨域以及遇到401响应的问题

    nginx配置cros跨域以及遇到401.500响应的问题 这是我Nginx的server配置: server {listen 80;server_name DataAnalysis;location ...

  7. Nginx 解决WebApi跨域二次请求以及Vue单页面问题

    Nginx 解决WebApi跨域二次请求以及Vue单页面问题 参考文章: (1)Nginx 解决WebApi跨域二次请求以及Vue单页面问题 (2)https://www.cnblogs.com/ji ...

  8. Nginx 代理转发阿里云OSS上传的实现代码

    这篇文章主要介绍了Nginx 代理转发阿里云OSS上传的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 前言 因为小程序上传需要https,服务器https用的是 ...

  9. Nginx 实现AJAX跨域请求

    AJAX从一个域请求另一个域会有跨域的问题.那么如何在nginx上实现ajax跨域请求呢?要在nginx上启用跨域请求,需要添加add_header Access-Control*指令.如下所示: 1 ...

最新文章

  1. MapReduce——shuffle
  2. 优秀设计师必备:视觉传达设计与视觉思维
  3. 最高效的进(线)程间通信机制--eventfd
  4. mysql 字符串搜_mysql – 在表中搜索字符串的SQL查询?
  5. 怎么生成a类型的对象 java_Java工程师考试题(答案)
  6. grafana 安装- 曲线图展示每秒新增数据量
  7. case when then else_SQL 优化大神玩转 MySQL函数系列_case_when 的坑
  8. 12. nc/netcat 用法举例
  9. zuul业务检查相关模块
  10. python网易云_Python分析网易云音乐近5年热门歌单
  11. 利用中文维基百科训练词向量模型
  12. 计算机英特尔显卡在哪找,Win10英特尔显卡设置在哪里 英特尔核芯显卡控制面板六大功能详解...
  13. mysql触发器安全吗_猎八哥浅谈MYSQL触发器
  14. 恒生期货交易时间(恒生指数期货交割日期)
  15. Sonic-Pi 初体验
  16. Welcome to Pete Brown's 10rem.net
  17. 测试/开发程序员的思考,突破变得更强......
  18. python模型预测控制_【模型工具】耦合python和 SWMM的城市排水系统模型预测算法...
  19. VMware下CentOS7最小化安装及配置
  20. kalilinux链接蓝牙音响_Kali-Linux安驱动、使用Blueman连接蓝牙耳机

热门文章

  1. rem、em、px的区别,详细介绍rem与px的转换
  2. cascode电流镜
  3. win10蓝牙开关消失,重新安装蓝牙驱动,功能恢复。
  4. 使用阿里百川和淘宝联盟进行私域用户管理授权(Android端)
  5. 来,你们想要的打卡功能
  6. 基于Linux系统的GTK+图形界面编程——扫雷游戏
  7. 04全志R58平台编译内核需要选择的配置
  8. Web前端-Vue ElementUI el-input组件绑定点击事件
  9. 哪些收入需要交个人所得税
  10. h桥控制电机刹车_(2条消息) h桥控制电机刹车