nginx 子请求

来源:互联网 发布:易语言mp3播放器源码 编辑:程序博客网 时间:2024/05/18 20:09

主要分析子请求的以下问题

1,子请求怎么创建

2,子请求怎么触发

3,子请求的配置

4,子请求的变量

5,子请求可否设置缓存

6,子请求的location会不会打印log


1,子请求怎么创建

  ngx_http_subrequest函数会创建子请求,调用形式为:

ngx_int_t  ngx_http_subrequest(ngx_http_request_t *r,

ngx_str_t *uri, 

ngx_str_t *args,

 ngx_http_request_t **psr,

ngx_http_post_subrequest_t *ps, 

ngx_uint_t flags)

第一个参数为创建子请求的主请求,

第二个参数为子请求的uri,

第三个参数为子请求的参数,

第四个参数为主请求创建的子请求指针

第五个参数为ngx_http_post_subrequest_t类型的结构体指针,主要目的是子请求在结束时做回调,通常用于向主请求传递一些信息

第六个参数为创建子请求时创建的flg,flag的值有  NGX_HTTP_SUBREQUEST_IN_MEMORY  NGX_HTTP_SUBREQUEST_WAITED


ngx_http_subrequest函数的流程为:

如果r->main->count的值大于65535 - 1000,则返回错误,也就是子请求只能最多有65535 - 1000

对子请求分配空间,对于子请求里面的变量赋值

其中sr->connection=r->connection,也就是说子请求和父请求公用一个connection,

对子请求创建上下文,sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);

对子请求的headers_out分配空间ngx_list_init(&sr->headers_out.headers, r->pool, 20,sizeof(ngx_table_elt_t)

cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
sr->main_conf = cscf->ctx->main_conf;
sr->srv_conf = cscf->ctx->srv_conf;
sr->loc_conf = cscf->ctx->loc_conf;
sr->pool = r->pool;
sr->headers_in = r->headers_in;

sr->request_body = r->request_body;

sr->stream = r->stream;

sr->method = NGX_HTTP_GET;(子请求只能是GET)
sr->http_version = r->http_version;

sr->request_line = r->request_line;

sr->unparsed_uri = r->unparsed_uri;
 sr->method_name = ngx_http_core_get_method;
 sr->http_protocol = r->http_protocol;

sr->variables = r->variables;(子请求可以使用父请求的所有变量)


    sr->log_handler = r->log_handler;

请求的这些配置都跟主请求一致
sr->uri = *uri;(函数传递下来的参数)这个uri什么使用用?还没有发现?

if (args) {

        sr->args = *args;(函数传递下来的参数)
    }

sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;这个标志表示把获取到的数据放到内存里面
sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;这个标志还没有弄清楚?

sr->main = r->main;
sr->parent = r;
sr->post_subrequest = ps;
sr->read_event_handler = ngx_http_request_empty_handler;
sr->write_event_handler = ngx_http_handler;

sr->internal = 1;子请求的internal设置的是1

 pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
    if (pr == NULL) {
        return NGX_ERROR;
    }
    pr->request = sr;
    pr->out = NULL;
    pr->next = NULL;
    if (r->postponed) {
        for (p = r->postponed; p->next; p = p->next) { /* void */ }
        p->next = pr;
    } else {
        r->postponed = pr;  把当前子请求加入到主请求的postponed中
    }

把子请求sr挂在主请求r->postponed下面,是一个链表结构

接着调用ngx_http_post_request,调用形式为ngx_http_post_request(sr, NULL)

传递的第一个参数为sr,新创建的子请求,第二个参数为空

该函数主要作用就是把当前创建的子请求加入到子请求的主请求的posted_requests



2,子请求怎么运行

可以看到子请求创建后主要被加入到主请求的posted_requests和postponed里面,接下来就查看这两个成员什么时候使用?

对于posted_requests成员,可以看到在ngx_http_run_posted_requests里面调用

ngx_http_run_posted_requests函数的执行流程为:

遍历 r->main->posted_requests然后执行每个子请求的write_event_handler,也就是ngx_http_handler

ngx_http_handler的调用形式为ngx_http_handler(ngx_http_request_t *r)

执行流程为:

子请求的r->internal为1

设置r->phase_handler = cmcf->phase_engine.server_rewrite_index;也就是让子请求从server_rewrite阶段开始执行

对于子请求做以下设置:

r->valid_location = 1; 什么作用?
r->gzip_tested = 0;
r->gzip_ok = 0;
r->gzip_vary = 0;

然后r->write_event_handler设置为ngx_http_core_run_phases;

调用 ngx_http_core_run_phases(r);

ngx_http_core_run_phases函数就是从r->phase_handler位置往后执行,也就是server_rewrite

需要说明的是:子请求会跳过NGX_HTTP_ACCESS_PHASE的处理函数,相关分析可以参考 ngx phasehanler文章


postponed 主要是在postpone_filter_module以及finalize_request时使用(暂时不分析)

ngx_http_run_posted_requests函数主要是在

ngx_http_process_request(ngx_http_request_t *r)

ngx_http_request_handler(ngx_event_t *ev)这两个函数调用,这个两个函数可以保证所有的子请求都会被执行到


3,子请求的配置

子请求在创建的时候会指向父请求的配置的指针,在server_rewrite之后会进行修改,如何修改,这篇暂不讨论


4,子请求的变量

子请求的变量和父请求的变量执行的是同一个地方,在解析配置阶段父请求的变量已经进行解析拼凑变量,并且把变量的值存储在对应的index里面,子请求会取到和父请求一样的变量值。


5,子请求可否设置缓存

 子请求可以在其匹配location里面设置缓存


6,子请求的location会不会打印log

      子请求默认情况下不会打印log,log_subrequest设置为on,会打印log。