zoukankan      html  css  js  c++  java
  • nginx&http 第三章 ngx 请求处理的 11 个阶段 --ngx_http_process_request& ngx_http_handler

    ngx_http_process_request

    如果设置了定时器则删除,既然所有的请求已经接收完毕,就不会再发生超时了
    重设连接的读写回调函数
    重设请求读事件回调函数
    调用 ngx_http_handler 处理 HTTP 请求的 11 个阶段
    调用 ngx_http_run_posted_requests 处理 posted_requests 队列中的 POST 请
    /*
    ngx_http_process_request方法负责在接收完HTTP头部后,第一次与各个HTTP模块共同按阶段处理请求,而对于ngx_http_request_handler方法,
    如果ngx_http_process_request没能处理完请求,这个请求上的事件再次被触发,那就将由此方法继续处理了。
    */
    //ngx_http_process_request_headers头部行解析完毕后调用函数ngx_http_process_request_header
    void
    ngx_http_process_request(ngx_http_request_t *r) 
    {
        ngx_connection_t  *c;
    
        c = r->connection;
    
    #if (NGX_HTTP_SSL)
    
        if (r->http_connection->ssl) {
            long                      rc;
            X509                     *cert;
            ngx_http_ssl_srv_conf_t  *sscf;
    
            if (c->ssl == NULL) {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client sent plain HTTP request to HTTPS port");
                ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
                return;
            }
    
            sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
    
            if (sscf->verify) {
                rc = SSL_get_verify_result(c->ssl->connection);
    
                if (rc != X509_V_OK
                    && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
                {
                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                  "client SSL certificate verify error: (%l:%s)",
                                  rc, X509_verify_cert_error_string(rc));
    
                    ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                           (SSL_get0_session(c->ssl->connection)));
    
                    ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
                    return;
                }
    
                if (sscf->verify == 1) {
                    cert = SSL_get_peer_certificate(c->ssl->connection);
    
                    if (cert == NULL) {
                        ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                      "client sent no required SSL certificate");
    
                        ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                           (SSL_get0_session(c->ssl->connection)));
    
                        ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
                        return;
                    }
    
                    X509_free(cert);
                }
            }
        }
    
    #endif
        /*
        由于现在已经开始准备调用各HTTP模块处理请求了,因此不再存在接收HTTP请求头部超时的问题,那就需要从定时器中把当前连接的读事件移除了。
        检查读事件对应的timer_set标志位,力1时表示读事件已经添加到定时器中了,这时需要调用ngx_del_timer从定时器中移除读事件;
         */
        if (c->read->timer_set) {//ngx_http_read_request_header中读取不到数据的时候返回NGX_AGIN,会添加定时器和读事件表示继续等待客户端数据到来
            ngx_del_timer(c->read, NGX_FUNC_LINE);
        }
    
    #if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
        r->stat_reading = 0;
        (void) ngx_atomic_fetch_add(ngx_stat_writing, 1);
        r->stat_writing = 1;
    #endif
    
    /*
    从现在开始不会再需要接收HTTP请求行或者头部,所以需要重新设置当前连接读/写事件的回调方法。在这一步骤中,将同时把读事件、写事件的回调
    方法都设置为ngx_http_request_handler方法,请求的后续处理都是通过ngx_http_request_handler方法进行的。
     */
        c->read->handler = ngx_http_request_handler; //由读写事件触发ngx_http_request_handler  //由epoll读事件在ngx_epoll_process_events触发
        c->write->handler = ngx_http_request_handler;   //由epoll写事件在ngx_epoll_process_events触发
    
    /*
    设置ngx_http_request_t结构体的read_event_handler方法gx_http_block_reading。当再次有读事件到来时,将会调用ngx_http_block_reading方法
    处理请求。而这里将它设置为ngx_http_block_reading方法,这个方法可认为不做任何事,它的意义在于,目前已经开始处理HTTP请求,除非某个HTTP模块重新
    设置了read_event_handler方法,否则任何读事件都将得不到处理,也可似认为读事件被阻 塞了。
    */
        r->read_event_handler = ngx_http_block_reading; //表示暂时不要读取客户端请求    
    
        /* ngx_http_process_request和ngx_http_request_handler这两个方法的共通之处在于,它们都会先按阶段调用各个HTTP模块处理请求,再处理post请求 */
        ngx_http_handler(r); //这里面会执行ngx_http_core_run_phases,执行11个阶段
    
    /*
    HTTP框架无论是调用ngx_http_process_request方法(首次从业务上处理请求)还是ngx_http_request_handler方法(TCP连接上后续的事件触发时)处理
    请求,最后都有一个步骤,就是调用ngx_http_run_posted_requests方法处理post请求
    
    11个阶段执行完毕后,调用ngx_http_run_posted_requests方法执行post请求,这里一般都是对subrequest进行处理
    */
        ngx_http_run_posted_requests(c); /*  */
    }
    

    2、处理 HTTP 请求的准备工作 -- ngx_http_handler

    在函数中,重新设置了读事件回调,那么请求的写事件回调是在 ngx_http_handler 函数中重设的

    //ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
    //ngx_http_run_posted_requests->ngx_http_handler
    void
    ngx_http_handler(ngx_http_request_t *r) /* 执行11个阶段的指定阶段 */
    {
        ngx_http_core_main_conf_t  *cmcf;
    
        r->connection->log->action = NULL;
    
        r->connection->unexpected_eof = 0;
    
    /*
        检查ngx_http_request_t结构体的internal标志位,如果internal为0,则从头部phase_handler执行;如果internal标志位为1,则表示请求当前需要做内部跳转,
    将要把结构体中的phase_handler序号置为server_rewrite_index。注意ngx_http_phase_engine_t结构体中的handlers动态数组中保存了请求需要经历的所有
    回调方法,而server_rewrite_index则是handlers数组中NGX_HTTP_SERVER_REWRITE_PHASE处理阶段的第一个ngx_http_phase_handler_t回调方法所处的位置。
        究竟handlers数组是怎么使用的呢?事实上,它要配合着ngx_http_request_t结构体的phase_handler序号使用,由phase_handler指定着请求将要执行
    的handlers数组中的方法位置。注意,handlers数组中的方法都是由各个HTTP模块实现的,这就是所有HTTP模块能够共同处理请求的原因。 
     */
        if (!r->internal) {
            
            switch (r->headers_in.connection_type) {
            case 0:
                r->keepalive = (r->http_version > NGX_HTTP_VERSION_10); //指明在1.0以上版本默认是长连接
                break;
    
            case NGX_HTTP_CONNECTION_CLOSE:
                r->keepalive = 0;
                break;
    
            case NGX_HTTP_CONNECTION_KEEP_ALIVE:
                r->keepalive = 1;
                break;
            }
        
            r->lingering_close = (r->headers_in.content_length_n > 0
                                  || r->headers_in.chunked); 
            /*
           当internal标志位为0时,表示不需要重定向(如刚开始处理请求时),将phase_handler序号置为0,意味着从ngx_http_phase_engine_t指定数组
           的第一个回调方法开始执行(了解ngx_http_phase_engine_t是如何将各HTTP模块的回调方法构造成handlers数组的)。
              */
            r->phase_handler = 0;
    
        } else {
    /* 
    在这一步骤中,把phase_handler序号设为server_rewrite_index,这意味着无论之前执行到哪一个阶段,马上都要重新从NGX_HTTP_SERVER_REWRITE_PHASE
    阶段开始再次执行,这是Nginx的请求可以反复rewrite重定向的基础。
    */
            cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
            r->phase_handler = cmcf->phase_engine.server_rewrite_index;
        }
    
        r->valid_location = 1;
    #if (NGX_HTTP_GZIP)
        r->gzip_tested = 0;
        r->gzip_ok = 0;
        r->gzip_vary = 0;
    #endif
    
        r->write_event_handler = ngx_http_core_run_phases;
        ngx_http_core_run_phases(r);  
    }

    然后这个函数通过请求的 internal 字段判断是否从 0 号回调开始执行最后,就要进入请求的 11 个阶段的处理了 -- ngx_http_core_run_phases

    /*  
        每个ngx_http_phases阶段对应的checker函数,处于同一个阶段的checker函数相同,见ngx_http_init_phase_handlers
        NGX_HTTP_SERVER_REWRITE_PHASE  -------  ngx_http_core_rewrite_phase
        NGX_HTTP_FIND_CONFIG_PHASE     -------  ngx_http_core_find_config_phase
        NGX_HTTP_REWRITE_PHASE         -------  ngx_http_core_rewrite_phase
        NGX_HTTP_POST_REWRITE_PHASE    -------  ngx_http_core_post_rewrite_phase
        NGX_HTTP_ACCESS_PHASE          -------  ngx_http_core_access_phase
        NGX_HTTP_POST_ACCESS_PHASE     -------  ngx_http_core_post_access_phase
        NGX_HTTP_TRY_FILES_PHASE       -------  NGX_HTTP_TRY_FILES_PHASE
        NGX_HTTP_CONTENT_PHASE         -------  ngx_http_core_content_phase
        其他几个阶段                   -------  ngx_http_core_generic_phase
    
        HTTP框架为11个阶段实现的checker方法  赋值见           ngx_http_init_phase_handlers
    ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
    ┃    阶段名称                  ┃    checker方法                   ┃
    ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
    ┃   NGX_HTTP_POST_READ_PHASE   ┃    ngx_http_core_generic_phase   ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP SERVER REWRITE PHASE ┃ngx_http_core_rewrite_phase       ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP FIND CONFIG PHASE    ┃ngx_http_core find config_phase   ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP REWRITE PHASE        ┃ngx_http_core_rewrite_phase       ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP POST REWRITE PHASE   ┃ngx_http_core_post_rewrite_phase  ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP PREACCESS PHASE      ┃ngx_http_core_generic_phase       ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP ACCESS PHASE         ┃ngx_http_core_access_phase        ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP POST ACCESS PHASE    ┃ngx_http_core_post_access_phase   ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP TRY FILES PHASE      ┃ngx_http_core_try_files_phase     ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP CONTENT PHASE        ┃ngx_http_core_content_phase       ┃
    ┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
    ┃NGX HTTP LOG PHASE            ┃ngx_http_core_generic_phase       ┃
    ┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
    */
    /*
    通常来说,在接收完HTTP头部后,是无法在一次Nginx框架的调度中处理完一个请求的。在第一次接收完HTTP头部后,HTTP框架将调度
    ngx_http_process_request方法开始处理请求,如果某个checker方法返回了NGX_OK,则将会把控制权交还给Nginx框架。当这个请求
    上对应的事件再次触发时,HTTP框架将不会再调度ngx_http_process_request方法处理请求,而是由ngx_http_request_handler方法
    开始处理请求。例如recv虽然把头部行内容读取完毕,并能解析完成,但是可能有携带请求内容,内容可能没有读完
    */
    //通过执行当前r->phase_handler所指向的阶段的checker函数
    //ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
    void
    ngx_http_core_run_phases(ngx_http_request_t *r) //执行该请求对于的阶段的checker(),并获取返回值
    {
        ngx_int_t                   rc;
        ngx_http_phase_handler_t   *ph;
        ngx_http_core_main_conf_t  *cmcf;
    
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    
        ph = cmcf->phase_engine.handlers;
    
        while (ph[r->phase_handler].checker) { //处于同一ngx_http_phases阶段的所有ngx_http_phase_handler_t的checker指向相同的函数,见ngx_http_init_phase_handlers
    /*
    handler方法其实仅能在checker方法中被调用,而且checker方法由HTTP框架实现,所以可以控制各HTTP模块实现的处理方法在不同的阶段中采用不同的调用行为
    
    ngx_http_request_t结构体中的phase_handler成员将决定执行到哪一阶段,以及下一阶段应当执行哪个HTTP模块实现的内容。可以看到请求的phase_handler成员
    会被重置,而HTTP框架实现的checker穷法也会修改phase_handler成员的值
    
    当checker方法的返回值非NGX_OK时,意味着向下执行phase_engine中的各处理方法;反之,当任何一个checker方法返回NGX_OK时,意味着把控制权交还
    给Nginx的事件模块,由它根据事件(网络事件、定时器事件、异步I/O事件等)再次调度请求。然而,一个请求多半需要Nginx事件模块多次地调度HTTP模
    块处理,也就是在该函数外设置的读/写事件的回调方法ngx_http_request_handler
    */
            // 所有的处理阶段回调函数构成了一个链表
            // NGX_HTTP_SERVER_REWRITE_PHASE    ngx_http_core_rewrite_phase
            // NGX_HTTP_FIND_CONFIG_PHASE        ngx_http_core_find_config_phase
            // NGX_HTTP_REWRITE_PHASE            ngx_http_core_rewrite_phase
            // NGX_HTTP_POST_REWRITE_PHASE        ngx_http_core_post_rewrite_phase
            // NGX_HTTP_PREACCESS_PHASE            ngx_http_core_generic_phase
            // NGX_HTTP_POST_READ_PHASE            ngx_http_limit_conn_handler
            // NGX_HTTP_ACCESS_PHASE            ngx_http_core_access_phase
            // NGX_HTTP_POST_ACCESS_PHASE        ngx_http_core_post_access_phase
            // NGX_HTTP_CONTENT_PHASE            ngx_http_core_content_phase
            // NGX_HTTP_TRY_FILES_PHASE            ngx_http_core_try_files_phase
            
            rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
    
     /* 直接返回NGX OK会使待HTTP框架立刻把控制权交还给epoll事件框架,不再处理当前请求,唯有这个请求上的事件再次被触发才会继续执行。*/
            if (rc == NGX_OK) { //执行phase_handler阶段的hecker  handler方法后,返回值为NGX_OK,则直接退出,否则继续循环执行checker handler
                return;
            }
        }
    }
  • 相关阅读:
    移动页面HTML5自适应手机屏幕宽度
    “流式”前端构建工具——gulp.js 简介
    HDU2602-Bone Collector
    HDU3535-AreYouBusy
    HDU1712-ACboy needs your help
    HDU3496-Watch The Movie
    HDU1171-Big Event in HDU
    POJ2533-Longest Ordered Subsequence
    HDU2084-数塔
    HDU2023-求平均成绩
  • 原文地址:https://www.cnblogs.com/codestack/p/12362938.html
Copyright © 2011-2022 走看看