• 05 proxy_pass 携带有 uri 的场景下面的处理


    前言

    这里主要是关注 proxy_pass 的配置, 对于 代理都上游服务的请求的相关处理的实现差异 

    比如 如下配置是否存在什么差异, 造成的结果是什么 

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

    现在假设存在一个上游服务 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"

    1. Breakpoint 9, ngx_http_proxy_create_request (r=0x7f8b34801c50)
    2. at src/http/modules/ngx_http_proxy_module.c:1207
    3. 1207 if (plcf->proxy_lengths && ctx->vars.uri.len) {
    4. (gdb) print ctx->vars
    5. $40 = {key_start = {len = 21,
    6. data = 0x7f8b33808f5b "http://localhost:8080/api/"}, schema = {len = 7,
    7. data = 0x7f8b33808f5b "http://localhost:8080/api/"}, host_header = {
    8. len = 14, data = 0x7f8b33808f62 "localhost:8080/api/"}, port = {len = 4,
    9. data = 0x7f8b33808f6c "8080/api/"}, uri = {len = 5,
    10. data = 0x7f8b33808f70 "/api/"}}
    11. (gdb) next
    12. 1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
    13. (gdb) next
    14. 1216 plcf->location.len : 0;
    15. (gdb) next
    16. 1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
    17. (gdb) next
    18. 1218 if (r->quoted_uri || r->space_in_uri || r->internal) {
    19. (gdb) print loc_len
    20. $41 = 5
    21. (gdb) c
    22. Continuing.
    23. Breakpoint 10, ngx_http_proxy_create_request (r=0x7f8b34801c50)
    24. at src/http/modules/ngx_http_proxy_module.c:1332
    25. 1332 if (plcf->proxy_lengths && ctx->vars.uri.len) {
    26. (gdb) next
    27. 1339 if (r->valid_location) {
    28. (gdb) next
    29. 1340 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
    30. (gdb) next
    31. 1343 if (escape) {
    32. (gdb) next
    33. 1349 b->last = ngx_copy(b->last, r->uri.data + loc_len,
    34. (gdb) print r->uri
    35. $42 = {len = 37,
    36. data = 0x7f8b34801804 "/api/HelloWorld/listFormWithoutHeader?param01=p01¶m02=p02 HTTP/1.1\r\nHost"}
    37. (gdb) print loc_len
    38. $43 = 5
    39. (gdb) print b->start
    40. $44 = (u_char *) 0x7f8b34803408 "GET /api/"
    41. (gdb) next
    42. 1353 if (r->args.len > 0) {
    43. (gdb) print b->start
    44. $45 = (u_char *) 0x7f8b34803408 "GET /api/HelloWorld/listFormWithoutHeader"
    45. (gdb) next
    46. 1354 *b->last++ = '?';
    47. (gdb) next
    48. 1355 b->last = ngx_copy(b->last, r->args.data, r->args.len);
    49. (gdb) next
    50. 1359 u->uri.len = b->last - u->uri.data;
    51. (gdb) print b->start
    52. $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 

    1. Breakpoint 9, ngx_http_proxy_create_request (r=0x7fdbf9000450)
    2. at src/http/modules/ngx_http_proxy_module.c:1207
    3. 1207 if (plcf->proxy_lengths && ctx->vars.uri.len) {
    4. (gdb) print ctx.vars
    5. $47 = {key_start = {len = 21,
    6. data = 0x7fdbf701eb5b "http://localhost:8080/api"}, schema = {len = 7,
    7. data = 0x7fdbf701eb5b "http://localhost:8080/api"}, host_header = {
    8. len = 14, data = 0x7fdbf701eb62 "localhost:8080/api"}, port = {len = 4,
    9. data = 0x7fdbf701eb6c "8080/api"}, uri = {len = 4,
    10. data = 0x7fdbf701eb70 "/api"}}
    11. (gdb) next
    12. 1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
    13. (gdb) next
    14. 1216 plcf->location.len : 0;
    15. (gdb) next
    16. 1215 loc_len = (r->valid_location && ctx->vars.uri.len) ?
    17. (gdb) next
    18. 1218 if (r->quoted_uri || r->space_in_uri || r->internal) {
    19. (gdb) print loc_len
    20. $48 = 5
    21. (gdb) c
    22. Continuing.
    23. Breakpoint 10, ngx_http_proxy_create_request (r=0x7fdbf9000450)
    24. at src/http/modules/ngx_http_proxy_module.c:1332
    25. 1332 if (plcf->proxy_lengths && ctx->vars.uri.len) {
    26. (gdb) next
    27. 1339 if (r->valid_location) {
    28. (gdb) next
    29. 1340 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
    30. (gdb) next
    31. 1343 if (escape) {
    32. (gdb) print b->start
    33. $49 = (u_char *) 0x7fdbf9001c08 "GET /api"
    34. (gdb) next
    35. 1349 b->last = ngx_copy(b->last, r->uri.data + loc_len,
    36. (gdb) next
    37. 1353 if (r->args.len > 0) {
    38. (gdb) print b->start
    39. $50 = (u_char *) 0x7fdbf9001c08 "GET /apiHelloWorld/listFormWithoutHeader"
    40. (gdb) next
    41. 1354 *b->last++ = '?';
    42. (gdb) next
    43. 1355 b->last = ngx_copy(b->last, r->args.data, r->args.len);
    44. (gdb) next
    45. 1359 u->uri.len = b->last - u->uri.data;
    46. (gdb) print b->start
    47. $51 = (u_char *) 0x7fdbf9001c08 "GET /apiHelloWorld/listFormWithoutHeader?param01=p01¶m02=p02"

    结论

    综合一下结论 

    在 proxy_pass 存在 uri 部分的场景下面 

    最终向上游服务器请求的路径是 ctx.uri + url中截取掉location之后的子串  

    和三个部分是有关系的, 一个是 proxy_pass 影响的是 ctx.uri 

    一个是请求的 url, 一个是 location 本身 

  • 相关阅读:
    Spring Cloud Circuit Breaker 使用示例
    老杨说运维 | 双态运维转型中的“数智”一体化管理(文末附现场视频)
    php操作服务器中json文件 进行读写操作用ajax交互
    一文了解企业云盘和大文件传输哪个更适合企业传输
    RuntimeError:Input, output and indices must be on the current device
    云服务器ip使用细节(公网、私有)
    【ACWing】273. 分级(配数学证明)
    mmcv的环境 真 TM 难配
    关于IDEA中gradle项目bootrun无法进入断点以及gradle配置页面不全的解决方案
    【Web安全】点击劫持漏洞
  • 原文地址:https://blog.csdn.net/u011039332/article/details/125582032