这里主要是关注 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 中获取是否有 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 中获取是否有 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 本身
完