• Nginx “邪恶” rewrite


    概述

    本文主要针对nginx rewrite指令困惑的地方进行讲解,中间会涉及部分原理部分,我尽量用通俗易懂的语言来形容

    功能讲解

    大致流程

        The ngx_http_rewrite_module module directives are processed in the following order:

        the directives of this module specified on the server level are executed sequentially;

        repeatedly:

      • location is searched based on a request URI;

      • the directives of this module specified inside the found location are executed sequentially;

      • the loop is repeated if a request URI was rewritten, but not more than 10 times.

    涉及phase
    •     NGX_HTTP_SERVER_REWRITE_PHASE,

    •     NGX_HTTP_FIND_CONFIG_PHASE,

    •     NGX_HTTP_REWRITE_PHASE,

    •     NGX_HTTP_POST_REWRITE_PHASE,

    环境:
    • /aaa内容aaa

    • /bbb内容bbb

    Example 1:
    server {
        listen   80;
        location /aaa {
     
        if ($http_user_agent ~ Mozilla) {
                rewrite /aaa /bbb; 
     
        }
        return 403;
     
        }
     
        location /bbb {
        return 402
        }
     
    }

    在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

    然后继续执行rewrite模块其他指令,执行到return 403后,该request在nginx中的处理完毕,返回403;

    因此浏览器收到应答码为403

    Example 2:
        server {
            listen   80;
            location /aaa {
     
            if ($http_user_agent ~ Mozilla) {
                    rewrite /aaa /bbb; 
     
            }
    #        return 403;
     
            }
     
            location /bbb {
            return 402
            }
     
        }

    在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb)

    rewrite模块执行完毕。因为所有rewrite模块的指令都执行完毕,进入POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase

    中,由于执行了rewrite指令,在函数ngx_http_script_regex_start_code中

    if (code->uri) {
        r->internal = 1;
        r->valid_unparsed_uri = 0;
        if (code->break_cycle) {//rewrite ....break 指令分支
            r->valid_location = 0;
            r->uri_changed = 0;
        else {
            r->uri_changed = 1;
        }
    }

    可以得知r->uri_changed=1,于是在函数ngx_http_core_post_rewrite_phase中执行如下流程

    r->uri_changes--;
    if (r->uri_changes == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "rewrite or internal redirection cycle "
                      "while processing "%V"", &r->uri);
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_OK;
    }
    r->phase_handler = ph->next;//ph->next为find_config_index,在ngx_http_init_phase_handlers中可见
     
     
    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
    r->loc_conf = cscf->ctx->loc_conf;

    由于重新进行server和location匹配,因此在上述例子中,浏览器收到的应答状态吗为402

    Example 3:
    server {
        listen   80;
        location /aaa {
     
        if ($http_user_agent ~ Mozilla) {
                rewrite /aaa /bbb break
     
        }
        return 403;
     
        }
     
        location /bbb {
            return 402
        }
     
    }

    在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

    由于rewrite break标记符存在,从rewrite指令的配置解析函数ngx_http_rewrite和rewrite模块的handler函数ngx_http_rewrite_handler中

    如下部分可以得知,将停止执行rewrite模块的其他一切指令;

    ngx_http_rewrite {
    ....
    ....
        if (cf->args->nelts == 4) {
            if (ngx_strcmp(value[3].data, "last") == 0) {
                last = 1;
            else if (ngx_strcmp(value[3].data, "break") == 0) {
                regex->break_cycle = 1;
                last = 1;
            else if (ngx_strcmp(value[3].data, "redirect") == 0) {
                regex->status = NGX_HTTP_MOVED_TEMPORARILY;
                regex->redirect = 1;
                last = 1;
            else if (ngx_strcmp(value[3].data, "permanent") == 0) {
                regex->status = NGX_HTTP_MOVED_PERMANENTLY;
                regex->redirect = 1;
                last = 1;
            else {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid parameter "%V"", &value[3]);
                return NGX_CONF_ERROR;
            }
    .....
    .....
    .....
        if (last) {
            code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
            if (code == NULL) {
                return NGX_CONF_ERROR;
            }
            *code = NULL;
        }
    }
     
     
    ngx_http_rewrite_handler
    {
    .....
    .....
        while (*(uintptr_t *) e->ip) {
            code = *(ngx_http_script_code_pt *) e->ip;
            code(e);
        }
        if (e->status < NGX_HTTP_BAD_REQUEST) {//如果rewrite指令后不是break和last标记,而是其他两个重定向标记,则从此处直接结束该request处理流程
            return e->status;
        }
        if (r->err_status == 0) {
            return e->status;
        }
        return r->err_status;
    .....
    .....
    }

    进入到POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2 可知r->uri_changed = 0;

    在ngx_http_core_post_rewrite_phase中会执行如下流程,因此会继续执行当前server 和 location 上下文中后续的handler,因此浏览器收到内容为bbb

    if (!r->uri_changed) {
        r->phase_handler++;
        return NGX_AGAIN;
    }
    Example 4:
    server {
        listen   80;
        location /aaa {
     
        if ($http_user_agent ~ Mozilla) {
                rewrite /aaa /bbb last; 
     
        }
        return 403;
     
        }
     
        location /bbb {
            return 402
        }
     
    }

    在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

    由于rewrite last标记符存在,停止执行rewrite模块的其他一切指令,参考example 3。

    进入到rewrite模块所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2可知r->uri_changed = 1;

    于是重新进行server和location匹配,因此在上述例子中,浏览器收到的内容的状态码为402

  • 相关阅读:
    注解
    使用反射机制调用属性和私有成员与代理模式的介绍
    动态代理模式
    SVN的安装与常用功能使用以及解决安装配置过程中的一些错误
    企业私服
    -Java-log4j
    List,Set,Map用法以及区别
    接口和抽象类有什么区别
    Dalvik opcodes
    外派公司或者外包公司,真的适合选择吗?
  • 原文地址:https://www.cnblogs.com/scottieyuyang/p/5722604.html
Copyright © 2020-2023  润新知