nginx http框架执行流程(3) - 准备执行引擎

2018-07-28 16:16:15

在成功接收完 HTTP 请求头后,Nginx 就进入了HTTP处理引擎(请参考前面文章),在事件机制的驱动下由众多 http模块联合处理客户端的请求,最终产生合适的响应数据。

处理引擎运行的很多时候都调用了ngx_http_finalize_request() 等函数,用来 "结束" 请求,但它其实只是操作请求结构体里的引用计数 count,只有引用计数为0才会真正地结束请求。

我们先来看一看 ngx_http_process_request() 函数。

void
ngx_http_process_request(ngx_http_request_t *r){
    ngx_connection_t  *c;
	// 获取读事件相关的连接对象
    c = r->connection;
    
    // 此时已经读取了完整的http请求头,可以开始处理请求了
    // 如果还在定时器红黑树里,那么就删除,不需要检查超时
    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }
    
    // 头读取完毕
    // 连接的读写事件handler都设置为ngx_http_request_handler
    // 内部会转调用r->write_event_handler / r->read_event_handler
    c->read->handler = ngx_http_request_handler;
    c->write->handler = ngx_http_request_handler;
    
    // 即忽略读事件,有数据也不会处理
    // 如果之后调用了丢弃或者读取body
    // ngx_http_discarded_request_body_handler
    // ngx_http_read_client_request_body_handler
    r->read_event_handler = ngx_http_block_reading;
    
    // in ngx_http_core_module.c
    // 启动引擎数组,即r->write_event_handler = ngx_http_core_run_phases
    //
    // 外部请求的引擎数组起始序号是0,从头执行引擎数组,即先从Post read开始
    // 内部请求,即子请求.跳过post read,直接从server rewrite开始执行,即查找server
    // 启动引擎数组处理请求,调用ngx_http_core_run_phases
    // 从phase_handler的位置开始调用模块处理
    ngx_http_handler(r);
    
    // 如果有子请求,那么都要处理
    // 处理主请求里延后处理的请求链表,直至处理完毕
    // r->main->posted_requests
    // 调用请求里的write_event_handler
    // 通常就是ngx_http_core_run_phases引擎数组处理请求
    ngx_http_run_posted_requests(c);
    
}

因为这时请求头已经读取完了,暂时不需要关注可读事件(除非再显示要求读取或丢弃请求体),所以必须把读事件移出定时器红黑树,避免触发不必要的超时事件。

由于上面的设置,之后连接上的事件由 ngx_http_request_handler() 来处理。

// 通常写事件就是ngx_http_core_run_phases引擎数组处理请求
static void
ngx_http_request_handler(ngx_event_t *ev){
    ngx_connection_t    *c;
    ngx_http_request_t  *r;

    // 获取读事件相关的连接对象和请求对象
    c = ev->data;
    r = c->data;

    // 有写事件就调用请求里的write_event_handler
    if (ev->write) {
        // write_event_handler通常就是ngx_http_core_run_phases引擎数组处理请求
        r->write_event_handler(r);

    } else {
        // 否则是读事件,调用read_event_handler
        r->read_event_handler(r);
    }
    
    ...
}

上面把事件里的读写事件转换为 http 机制里的请求处理函数,又由于在 ngx_http_process_request() 里吧读事件设置为 ngx_http_block_reading(),所以不会真的处理读事件。

ngx_http_process_request() 的最后调用了 ngx_http_handler(),它启动了处理引擎。

void ngx_http_handler(ngx_http_request_t *r){
    ngx_http_core_main_conf_t  *cmcf;

    // 外部请求设置keepalive、lingering_close
    if (!r->internal) {
    	...
        // 如果有数据或者是chunked,那么需要lingering_close,等待数据
        r->lingering_close = (r->headers_in.content_length_n > 0
                              || r->headers_in.chunked);

        // 重要!!设置请求的引擎数组起始序号,从头执行引擎数组
        // 即先从Post read开始
        r->phase_handler = 0;

    } else {
        // 内部请求,即子请求
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

        // 跳过post read,直接从server rewrite开始执行,即查找server
        r->phase_handler = cmcf->phase_engine.server_rewrite_index;
    }

    // 启动引擎数组,即r->write_event_handler = ngx_http_core_run_phases
    r->write_event_handler = ngx_http_core_run_phases;

    // 启动引擎数组处理请求
    // 从phase_handler的位置开始调用模块处理
    ngx_http_core_run_phases(r);
}

那么如下下次再有写事件发生就会调用 ngx_http_request_handler() 然后调用 write_event_handler()函数(其实就是 ngx_http_core_run_phases)。

// 启动引擎数组处理请求
// 从phase_handler的位置开始调用模块处理
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
    ngx_int_t                   rc;
    ngx_http_phase_handler_t   *ph;
    ngx_http_core_main_conf_t  *cmcf;

    // 得到core main配置
    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    // 获取引擎里的handler数组
    ph = cmcf->phase_engine.handlers;

    // 从phase_handler的位置开始调用模块处理
    // 外部请求的引擎数组起始序号是0,从头执行引擎数组,即先从Post read开始
    // 内部请求,即子请求.跳过post read,直接从server rewrite开始执行,即查找server
    while (ph[r->phase_handler].checker) {

        // 调用引擎数组里的checker
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

        // checker会检查handler的返回值
        // 如果handler返回again/done那么就返回ok
        // 退出引擎数组的处理
        // 由于r->write_event_handler = ngx_http_core_run_phases
        // 当再有写事件时会继续从之前的模块执行
        //
        // 如果checker返回again,那么继续在引擎数组里执行
        // 模块由r->phase_handler指定,可能会有阶段的跳跃
        if (rc == NGX_OK) {
            return;
        }
    }
}

读者可以结合 http模块开发(7) - 处理引擎 来阅读。

流程图大致如下


备注

1.测试环境centos7 64位,nginx版本为 1.14.0。
2..原文地址http://www.freecls.com/a/2712/e3


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。