zoukankan      html  css  js  c++  java
  • [nginx] nginx源码分析--proxy模式下nginx的自动重定向auto_redirect

     

    描述

    我们配置了一个proxy模式下的nginx,

        upstream backend-test {
            server 127.0.0.1:80;
        }
        server {
            listen 8080;
            location = /nginx/hwwc/ {
                    proxy_pass http://backend-test;
                    proxy_redirect off;
            }
            location / {
                    return 500;
            }
        }

    访问 http://t103:8080/nginx/hwwc/ 可以正常访问80端口的服务. 访问curl http://t103:8080/nginx/hwwc 的时候, 会返回301重定向. 他们的区别是结尾是否有一个"/"

    ┬─[tong@T7:~/Src/thirdparty/nginx.git]─[07:13:29 PM]
    ╰─>$ curl http://t103:8080/nginx/hwwc
    <html>
    <head><title>301 Moved Permanently</title></head>
    <body bgcolor="white">
    <center><h1>301 Moved Permanently</h1></center>
    <hr><center>nginx/1.12.2</center>
    </body>
    </html>

    结论: 这个问题的原因是, 访问hwwc时触发了nginx的auto_rediect功能. 将请求重定向到了hwwc/

    分析过程如下:

    调试日志

    首先打开nginx的调试.  使用--with-debug选项编译的nginx可以打开此功能, 如下配置:

    参考:https://nginx.org/en/docs/ngx_core_module.html#debug_connection

    events {
            debug_connection 192.168.7.1;
    }

    在error.log里能看见如下日志: (摘录关键内容)

    ... ...
    2019/09/02 18:37:49 [debug] 23137#0: *70 test location: "/"
    2019/09/02 18:37:49 [debug] 23137#0: *70 test location: "nginx/hwwc/"
    2019/09/02 18:37:49 [debug] 23137#0: *70 using configuration "=/nginx/hwwc/"
    2019/09/02 18:37:49 [debug] 23137#0: *70 http cl:-1 max:1048576
    2019/09/02 18:37:49 [debug] 23137#0: *70 http finalize request: 301, "/nginx/hwwc?" a:1, c:1
    2019/09/02 18:37:49 [debug] 23137#0: *70 http special response: 301, "/nginx/hwwc?"
    2019/09/02 18:37:49 [debug] 23137#0: *70 http set discard body
    2019/09/02 18:37:49 [debug] 23137#0: *70 xslt filter header
    2019/09/02 18:37:49 [debug] 23137#0: *70 posix_memalign: 000055830C085F80:4096 @16
    2019/09/02 18:37:49 [debug] 23137#0: *70 HTTP/1.1 301 Moved Permanently
    Server: nginx/1.12.2
    Date: Mon, 02 Sep 2019 10:37:49 GMT
    Content-Type: text/html
    Content-Length: 185
    Location: http://t103:8080/nginx/hwwc/
    Connection: keep-alive

    通过上边的日志我们能见到, nginx在location"/" 与 "nginx/hwwc/" 中进行选择, 最后选择了"nginx/hwwc/", 然后触发了301.

    代码分析

    根据上边的日志, 我们通过主要的的关键字"test location" 和 "using configuration" 定位到如下代码:

    nginx/src/http/ngx_http_core_module.c::ngx_http_core_find_static_location():1443

            if (len + 1 == (size_t) node->len && node->auto_redirect) {
                r->loc_conf = (node->exact) ? node->exact->loc_conf:
                                              node->inclusive->loc_conf;
                rv = NGX_DONE;
            }

    在location选择的时候, 如果URI字符串比location字符串多了一个字符(也就是"/"),并且前边的字符都相等, 同时node结构体的变量auto_redirect也是true的. 就认为命中了当前location.

    也就是说URI"hwwc"会在精确匹配location的检查中匹配到location"hwwc/"

    nginx/src/http/ngx_http.c::ngx_http_create_locations_tree():1093

        node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
                               || (lq->inclusive && lq->inclusive->auto_redirect));

    nginx的全局代码中有两个auto_redirect, 一个是(一)中的node结构体. 另一个是config中的结构体.

    node中的结构体会通过config中的设置进行赋值. 如该段代码所述.

    nginx/src/http/modules/ngx_http_proxy_module.c::ngx_http_proxy_pass():3594

        if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
            clcf->auto_redirect = 1;
        }

    config中的auto_redirect, 当检测到location以"/"结尾的时候, 会自动赋值auto_redirect 为true, 并通过(二)传递到运行时.

    这段赋值代码, 除了在proxy模块中, 同时还存在与fastcgi, grpc, memcached, scgi, uwsgi模块中.

    nginx/src/http/ngx_http_core_module.h

    struct ngx_http_core_loc_conf_s {
        ... ...
        unsigned      auto_redirect:1;
        ngx_flag_t    absolute_redirect;       /* absolute_redirect */
        ngx_flag_t    server_name_in_redirect; /* server_name_in_redirect */
        ngx_flag_t    port_in_redirect;        /* port_in_redirect */
        ... ...
    }

    nginx/src/http/ngx_http_core_module.c

    static ngx_command_t  ngx_http_core_commands[] = {
        { ngx_string("absolute_redirect"),
        ... ...
        { ngx_string("server_name_in_redirect"),
         ... ...
        { ngx_string("port_in_redirect"),
        ... ...
    }

    分析配置流程中的代码. location中与redirect相关的配置大概一共有四个, 其中auto_redirect是不可配置的. 其他三个可以通过配置文件设置. 但是均与auto_redirect没有逻辑耦合关系.

    综上. auto_redirect是不可通过配置修改的. 由URI的结尾是否有"/"自动设置.

    如果要改变这一行为,需要进行代码基本的修改。 

    通过官方文档印证

    查看, ngnix的官方文档, 针对该问题有如下的描述,和解决建议. 与我们通过源码进行的分析保持一直:

    https://nginx.org/en/docs/http/ngx_http_core_module.html#location

     如果, 要屏蔽这个重定向问题, 应该明确的对不带"/"的location进行指定.

     

    另外, 

    除了以上提到的几个配置, 还有一个proxy_redirect的配置. 

    https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect

    通过简单测试,发现当前场景下,该配置并不生效. 应该是由于我们这个场景下个redirect使用proxy发的. 而这个配置项

    是针对backend发来的redirect消息进行修改的.

    以后可以读一下代码进行确认. 目前先通过测试做这样的黑盒判断.

    其他

    serverfault上也有人提出同样的问题. 结论与我们的分析一致.

    https://serverfault.com/questions/759762/how-to-stop-nginx-301-auto-redirect-when-trailing-slash-is-not-in-uri

  • 相关阅读:
    Java8新特性详解
    RedisTemplate详解
    RestTemplate详解
    windows中将多个文本文件合并为一个文件
    commons-lang 介绍
    commons-cli介绍
    commons-collections介绍
    commons-codec介绍
    commons-beanutils介绍
    commons-io介绍
  • 原文地址:https://www.cnblogs.com/hugetong/p/11448921.html
Copyright © 2011-2022 走看看