06 nginx 处理转发其他域的处理 以及 proxy_redirect
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的主要内容,如果未能解决你的问题,请参考以下文章