• 06 nginx 处理转发其他域的处理 以及 proxy_redirect


    前言

    容器端口映射导致 302 存在问题 以及 nginx 对于 302 的 Location 的重写

    中描述了如果 上游服务 sendRedirect 到所在域的其他服务之后, 来到 nginx 这一层, nginx 会将这个转发的服务更新为 nginx 所在的域 

    那么 假设上游服务 sendRedirect 到其他域的服务呢 ? 

    另外 就是在 探究这个问题的时候, 使用了一下 proxy_redirect, 这个 proxy_redirect 又是如何处理的呢?

    以下截图, 调试基于 nginx-1.18.0

    测试用例

    1. location ^~ /api/ {
    2. root html;
    3. index index.html index.htm;
    4. proxy_pass http://localhost:8080/;
    5. }

    sendRedirect 的服务, 是部署在 8080 端口上面 

    通过 nginx 访问发现出现 302, 跳转的域是 给定的目标域, nginx 没有重写 

    nginx 对于其他非上游域的服务的302的处理 

    location 的重写模块这里有一个对于域的判断, 如果 不是当前域直接 DECLINED, 不走后面的 rewrite 的处理 

    另外还有一个细节是 这个流程的 location 还是存放在 request 的 header 列表, 没有写到 request.headers_out.location 里面 

    响应的 location 和 proxy_pass 的 域不一致, 直接走 DECLINED 

    1. Breakpoint 1, ngx_http_proxy_rewrite_complex_handler (r=0x7f98e2000a50,
    2. h=0x7f98e2001000, prefix=0, len=54, pr=0x7f98e0806ac0)
    3. at src/http/modules/ngx_http_proxy_module.c:2630
    4. 2630 if (pattern.len > len
    5. (gdb) print pattern
    6. $1 = {len = 22, data = 0x7f98e0803b5b "http://localhost:8080/"}
    7. (gdb) print h->value
    8. $2 = {len = 54,
    9. data = 0x7f98e2002859 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
    10. (gdb) list
    11. 2625
    12. 2626 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
    13. 2627 return NGX_ERROR;
    14. 2628 }
    15. 2629
    16. 2630 if (pattern.len > len
    17. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    18. 2632 pattern.len) != 0)
    19. 2633 {
    20. 2634 return NGX_DECLINED;
    21. (gdb) next
    22. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    23. (gdb) next
    24. 2632 pattern.len) != 0)
    25. (gdb) next
    26. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    27. (gdb) next
    28. 2632 pattern.len) != 0)
    29. (gdb) next
    30. 2630 if (pattern.len > len
    31. (gdb) next
    32. 2634 return NGX_DECLINED;

    proxy_redirect

    增加 proxy_redirect 的配置如下 

    1. location ^~ /api/ {
    2. root html;
    3. index index.html index.htm;
    4. proxy_pass http://localhost:8080/;
    5. proxy_redirect 80 83;
    6. proxy_redirect http://localhost http://127.0.0.1;
    7. }

    来到 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

    1. Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050,
    2. h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)
    3. at src/http/modules/ngx_http_proxy_module.c:2630
    4. 2630 if (pattern.len > len
    5. (gdb) bt
    6. #0 ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050,
    7. h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)
    8. at src/http/modules/ngx_http_proxy_module.c:2630
    9. #1 0x000000010aacb893 in ngx_http_proxy_rewrite_redirect (r=0x7fd48a814050,
    10. h=0x7fd48a814600, prefix=0)
    11. at src/http/modules/ngx_http_proxy_module.c:2524
    12. #2 0x000000010aa894ed in ngx_http_upstream_rewrite_location (
    13. r=0x7fd48a814050, h=0x7fd48a82ee70, offset=0)
    14. at src/http/ngx_http_upstream.c:5100
    15. #3 0x000000010aa8d9bd in ngx_http_upstream_process_headers (r=0x7fd48a814050,
    16. u=0x7fd48a82e5e0) at src/http/ngx_http_upstream.c:2806
    17. #4 0x000000010aa8ede7 in ngx_http_upstream_process_header (r=0x7fd48a814050,
    18. u=0x7fd48a82e5e0) at src/http/ngx_http_upstream.c:2432
    19. #5 0x000000010aa8e7e5 in ngx_http_upstream_handler (ev=0x10ac1f208)
    20. at src/http/ngx_http_upstream.c:1286
    21. #6 0x000000010aa57c10 in ngx_kqueue_process_events (cycle=0x7fd48a80c050,
    22. timer=13648, flags=1) at src/event/modules/ngx_kqueue_module.c:669
    23. #7 0x000000010aa479f6 in ngx_process_events_and_timers (cycle=0x7fd48a80c050)
    24. at src/event/ngx_event.c:247
    25. #8 0x000000010aa55ac5 in ngx_worker_process_cycle (cycle=0x7fd48a80c050,
    26. data=0x0) at src/os/unix/ngx_process_cycle.c:750
    27. #9 0x000000010aa52cfa in ngx_spawn_process (cycle=0x7fd48a80c050,
    28. proc=0x10aa55a10 <ngx_worker_process_cycle>, data=0x0,
    29. name=0x10ab1da1e "worker process", respawn=-3)
    30. at src/os/unix/ngx_process.c:199
    31. #10 0x000000010aa54be7 in ngx_start_worker_processes (cycle=0x7fd48a80c050,
    32. n=1, type=-3) at src/os/unix/ngx_process_cycle.c:359
    33. #11 0x000000010aa54558 in ngx_master_process_cycle (cycle=0x7fd48a80c050)
    34. at src/os/unix/ngx_process_cycle.c:131
    35. #12 0x000000010aa0c8ba in main (argc=3, argv=0x7ffee51f4548)
    36. at src/core/nginx.c:382
    37. (gdb) frame 1
    38. #1 0x000000010aacb893 in ngx_http_proxy_rewrite_redirect (r=0x7fd48a814050,
    39. h=0x7fd48a814600, prefix=0)
    40. at src/http/modules/ngx_http_proxy_module.c:2524
    41. 2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
    42. (gdb) print pr[0]
    43. $3 = {handler = 0x10aac8a80 <ngx_http_proxy_rewrite_complex_handler>,
    44. pattern = {complex = {value = {len = 2, data = 0x7fd48a808fef "80"},
    45. flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}},
    46. regex = 0x2}, replacement = {value = {len = 2,
    47. data = 0x7fd48a808ff2 "83"}, flushes = 0x0, lengths = 0x0, values = 0x0,
    48. u = {size = 0}}}
    49. (gdb) print pr[1]
    50. $4 = {handler = 0x10aac8a80 <ngx_http_proxy_rewrite_complex_handler>,
    51. pattern = {complex = {value = {len = 16,
    52. data = 0x7fd48a809097 "http://localhost"}, flushes = 0x0,
    53. lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x10},
    54. replacement = {value = {len = 16, data = 0x7fd48a8090a8 "http://127.0.0.1"},
    55. flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
    56. (gdb) print plcf->redirects->nelts
    57. $5 = 2
    58. (gdb) print h->value
    59. $6 = {len = 54,
    60. data = 0x7fd48a82f059 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
    61. (gdb) frame0
    62. Undefined command: "frame0". Try "help".
    63. (gdb) frame 0
    64. #0 ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050,
    65. h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a8090c0)
    66. at src/http/modules/ngx_http_proxy_module.c:2630
    67. 2630 if (pattern.len > len
    68. (gdb) next
    69. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    70. (gdb) next
    71. 2632 pattern.len) != 0)
    72. (gdb) next
    73. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    74. (gdb) next
    75. 2632 pattern.len) != 0)
    76. (gdb) next
    77. 2630 if (pattern.len > len
    78. (gdb) next
    79. 2634 return NGX_DECLINED;
    80. (gdb) next
    81. 2642 }
    82. (gdb) print pattern
    83. $7 = {len = 2, data = 0x7fd48a808fef "80"}
    84. (gdb) c
    85. Continuing.
    86. Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fd48a814050,
    87. h=0x7fd48a814600, prefix=0, len=54, pr=0x7fd48a809128)
    88. at src/http/modules/ngx_http_proxy_module.c:2630
    89. 2630 if (pattern.len > len
    90. (gdb) print pattern
    91. $8 = {len = 16, data = 0x7fd48a809097 "http://localhost"}
    92. (gdb) print h->value
    93. $9 = {len = 54,
    94. data = 0x7fd48a82f059 "http://localhost:8083/HelloWorld/listFormWithoutHeader"}
    95. (gdb) next
    96. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    97. (gdb) next
    98. 2632 pattern.len) != 0)
    99. (gdb) next
    100. 2631 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
    101. (gdb) next
    102. 2632 pattern.len) != 0)
    103. (gdb) next
    104. 2630 if (pattern.len > len
    105. (gdb) next
    106. 2637 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
    107. (gdb) next
    108. 2641 return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
    109. (gdb) next
    110. 2642 }
    111. (gdb) print h->value
    112. $10 = {len = 54,
    113. 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/" 的替换操作

    1. location ^~ /api/ {
    2. root html;
    3. index index.html index.htm;
    4. proxy_pass http://localhost:8080/;
    5. }

    可以看到 确实是存在一条  "http://localhost:8080/" -> "/api/" 的替换操作

    1. Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7fec8a800450,
    2. h=0x7fec8a800a00, prefix=0, len=54, pr=0x7fec89001ec0)
    3. at src/http/modules/ngx_http_proxy_module.c:2630
    4. 2630 if (pattern.len > len
    5. (gdb) frame 1
    6. #1 0x0000000100d2d893 in ngx_http_proxy_rewrite_redirect (r=0x7fec8a800450,
    7. h=0x7fec8a800a00, prefix=0)
    8. at src/http/modules/ngx_http_proxy_module.c:2524
    9. 2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
    10. (gdb) print pr[0]
    11. $11 = {handler = 0x100d2aa80 <ngx_http_proxy_rewrite_complex_handler>,
    12. pattern = {complex = {value = {len = 22,
    13. data = 0x7fec88008f5b "http://localhost:8080/"}, flushes = 0x0,
    14. lengths = 0x0, values = 0x0, u = {size = 0}}, regex = 0x16},
    15. replacement = {value = {len = 5, data = 0x7fec88007a94 "/api/"},
    16. flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}}}
    17. (gdb) print plcf->redirects->nelts
    18. $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 

    1. location ^~ /api/ {
    2. root html;
    3. index index.html index.htm;
    4. proxy_pass http://localhost:8080/;
    5. proxy_redirect 80 83;
    6. }

    可以发现 上游服务响应的是上游服务所在的域的地址, 然后 nginx 拿到该地址之后 没有更新域为当前域 

    因为 已经存在 proxy_redirect, 没有添加 "http://localhost:8080/" -> "/api/" 的替换操作 

    拿到运行时的数据信息, 可以看到没有 "http://localhost:8080/" -> "/api/" 的替换操作 

    1. Breakpoint 2, ngx_http_proxy_rewrite_complex_handler (r=0x7ffd25000a50,
    2. h=0x7ffd25001000, prefix=0, len=54, pr=0x7ffd2400f820)
    3. at src/http/modules/ngx_http_proxy_module.c:2630
    4. 2630 if (pattern.len > len
    5. (gdb) frame 1
    6. #1 0x0000000107375893 in ngx_http_proxy_rewrite_redirect (r=0x7ffd25000a50,
    7. h=0x7ffd25001000, prefix=0)
    8. at src/http/modules/ngx_http_proxy_module.c:2524
    9. 2524 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
    10. (gdb) print plcf->redirects->nelts
    11. $13 = 1
    12. (gdb) print pr[0]
    13. $14 = {handler = 0x107372a80 <ngx_http_proxy_rewrite_complex_handler>,
    14. pattern = {complex = {value = {len = 2, data = 0x7ffd2400f7ef "80"},
    15. flushes = 0x0, lengths = 0x0, values = 0x0, u = {size = 0}},
    16. regex = 0x2}, replacement = {value = {len = 2,
    17. data = 0x7ffd2400f7f2 "83"}, flushes = 0x0, lengths = 0x0, values = 0x0,
    18. u = {size = 0}}}
    19. (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/"

  • 相关阅读:
    双向链表专题
    软件测试/校招推荐丨鼎捷软件股份有限公司岗位开放
    10.1select并发服务器以及客户端
    字符驱动开发2
    路由配置与mongoose模型构建
    Java刷题面试系列习题(三)
    【WMS仓库管理系统】基础概念:库位、库区、库位
    python打包加密工具:Pyinstaller和Nuitka
    根据平面abcd 参数生成平面点云(附 open3d 代码)
    uniapp合法域名配置
  • 原文地址:https://blog.csdn.net/u011039332/article/details/125584534