05 proxy_pass 携带有 uri 的场景下面的处理
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了05 proxy_pass 携带有 uri 的场景下面的处理相关的知识,希望对你有一定的参考价值。
前言
这里主要是关注 proxy_pass 的配置, 对于 代理都上游服务的请求的相关处理的实现差异
比如 如下配置是否存在什么差异, 造成的结果是什么
location ^~ /api/
root html;
index index.html index.htm;
proxy_pass http://localhost:8080/api/;
location ^~ /api/
root html;
index index.html index.htm;
proxy_pass http://localhost:8080/api;
现在假设存在一个上游服务 http://localhost:8080/api/HelloWorld/listFormWithoutHeader?param01=p01¶m02=p02
上面的配置是可以正常代理的, 但是 下面的配置响应的是 404
本文探讨的就是类似的问题
以下截图, 调试基于 nginx-1.18.0
proxy_pass http://localhost:8080/api/ 的场景
这里首先是从 proxy_pass 中获取是否有 uri 参数, 这里为 "/api/"
然后获取到的 loc_len 为 匹配到的 location 的字符串的长度, 这里为 "/api/" 长度为 5
然后 下面是拼接 ctx.vars.uri 和 请求路径截取掉 location 匹配的字符串, "/api/" + "HelloWorld/listFormWithoutHeader", 最终得到路径 "/api/HelloWorld/listFormWithoutHeader"
Breakpoint 9, ngx_http_proxy_create_request (r=0x7f8b34801c50)
at src/http/modules/ngx_http_proxy_module.c:1207
1207 if (plcf->proxy_lengths && ctx->vars.uri.len)
(gdb) print ctx->vars
$40 = key_start = len = 21,
data = 0x7f8b33808f5b "http://localhost:8080/api/", schema = len = 7,
data = 0x7f8b33808f5b "http://localhost:8080/api/", host_header =
len = 14, data = 0x7f8b33808f62 "localhost:8080/api/", port = len = 4,
data = 0x7f8b33808f6c "8080/api/", uri = len = 5,
data = 0x7f8b33808f70 "/api/"
(gdb) next
1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
(gdb) next
1216 plcf->location.len : 0;
(gdb) next
1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
(gdb) next
1218 if (r->quoted_uri || r->space_in_uri || r->internal)
(gdb) print loc_len
$41 = 5
(gdb) c
Continuing.
Breakpoint 10, ngx_http_proxy_create_request (r=0x7f8b34801c50)
at src/http/modules/ngx_http_proxy_module.c:1332
1332 if (plcf->proxy_lengths && ctx->vars.uri.len)
(gdb) next
1339 if (r->valid_location)
(gdb) next
1340 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
(gdb) next
1343 if (escape)
(gdb) next
1349 b->last = ngx_copy(b->last, r->uri.data + loc_len,
(gdb) print r->uri
$42 = len = 37,
data = 0x7f8b34801804 "/api/HelloWorld/listFormWithoutHeader?param01=p01¶m02=p02 HTTP/1.1\\r\\nHost"
(gdb) print loc_len
$43 = 5
(gdb) print b->start
$44 = (u_char *) 0x7f8b34803408 "GET /api/"
(gdb) next
1353 if (r->args.len > 0)
(gdb) print b->start
$45 = (u_char *) 0x7f8b34803408 "GET /api/HelloWorld/listFormWithoutHeader"
(gdb) next
1354 *b->last++ = '?';
(gdb) next
1355 b->last = ngx_copy(b->last, r->args.data, r->args.len);
(gdb) next
1359 u->uri.len = b->last - u->uri.data;
(gdb) print b->start
$46 = (u_char *) 0x7f8b34803408 "GET /api/HelloWorld/listFormWithoutHeader?param01=p01¶m02=p02"
proxy_pass http://localhost:8080/api 的场景
同样的道理
这里首先是从 proxy_pass 中获取是否有 uri 参数, 这里为 "/api"
然后获取到的 loc_len 为 匹配到的 location 的字符串的长度, 这里为 "/api/" 长度为 5
然后 下面是拼接 ctx.vars.uri 和 请求路径截取掉 location 匹配的字符串, "/api" + "HelloWorld/listFormWithoutHeader", 最终得到路径 "/apiHelloWorld/listFormWithoutHeader"
然后 在上游服务那边, 找不到对应的服务, 因此 响应的是 404
Breakpoint 9, ngx_http_proxy_create_request (r=0x7fdbf9000450)
at src/http/modules/ngx_http_proxy_module.c:1207
1207 if (plcf->proxy_lengths && ctx->vars.uri.len)
(gdb) print ctx.vars
$47 = key_start = len = 21,
data = 0x7fdbf701eb5b "http://localhost:8080/api", schema = len = 7,
data = 0x7fdbf701eb5b "http://localhost:8080/api", host_header =
len = 14, data = 0x7fdbf701eb62 "localhost:8080/api", port = len = 4,
data = 0x7fdbf701eb6c "8080/api", uri = len = 4,
data = 0x7fdbf701eb70 "/api"
(gdb) next
1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
(gdb) next
1216 plcf->location.len : 0;
(gdb) next
1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
(gdb) next
1218 if (r->quoted_uri || r->space_in_uri || r->internal)
(gdb) print loc_len
$48 = 5
(gdb) c
Continuing.
Breakpoint 10, ngx_http_proxy_create_request (r=0x7fdbf9000450)
at src/http/modules/ngx_http_proxy_module.c:1332
1332 if (plcf->proxy_lengths && ctx->vars.uri.len)
(gdb) next
1339 if (r->valid_location)
(gdb) next
1340 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
(gdb) next
1343 if (escape)
(gdb) print b->start
$49 = (u_char *) 0x7fdbf9001c08 "GET /api"
(gdb) next
1349 b->last = ngx_copy(b->last, r->uri.data + loc_len,
(gdb) next
1353 if (r->args.len > 0)
(gdb) print b->start
$50 = (u_char *) 0x7fdbf9001c08 "GET /apiHelloWorld/listFormWithoutHeader"
(gdb) next
1354 *b->last++ = '?';
(gdb) next
1355 b->last = ngx_copy(b->last, r->args.data, r->args.len);
(gdb) next
1359 u->uri.len = b->last - u->uri.data;
(gdb) print b->start
$51 = (u_char *) 0x7fdbf9001c08 "GET /apiHelloWorld/listFormWithoutHeader?param01=p01¶m02=p02"
结论
综合一下结论
在 proxy_pass 存在 uri 部分的场景下面
最终向上游服务器请求的路径是 ctx.uri + url中截取掉location之后的子串
和三个部分是有关系的, 一个是 proxy_pass 影响的是 ctx.uri
一个是请求的 url, 一个是 location 本身
完
以上是关于05 proxy_pass 携带有 uri 的场景下面的处理的主要内容,如果未能解决你的问题,请参考以下文章
Nginx 每个位置/将重写的 uri 传递给 proxy_pass
单独服务器上的 nginx proxy_pass 到多个 Rails 应用程序,乘客独立在不同的盒子中具有子 URI
如何更改 nginx proxy_pass 中的 request_uri?