文档章节

nginx源码分析——http处理流程

hncscwc
 hncscwc
发布于 2016/07/15 21:29
字数 992
阅读 348
收藏 6

1. http处理流程概述

nginx对于http请求处理的大概流程是:接收客户端发起的连接,然后接收并解析http请求行,接收并解析http头部;再根据配置文件nginx.conf找到相关http模块,使这些模块依次合作处理http请求,最后发送http响应并结束http请求。

在整个http请求处理过程中,nginx通过连接的读写事件,以及定时器机制,异步回调完成其处理流程。

2. http新连接的建立

事件模块一文中我们知道,当新连接建立后会回调对应侦听的处理方法。对于http模块,该回调方法为ngx_http_init_connection。在该方法中,主要完成的事情是:设置连接的读事件回调处理方法为ngx_http_wait_request_handler,设置连接的写事件回调处理方法为ngx_http_empty_handler;然后查看读事件是否已经准备好,即连接对应的套接字缓冲区上是否已经接收到用户的请求数据了,如果是,则直接调用ngx_http_wait_request_handler进入下一处理步骤;如果还没有准备好,则对连接的读事件设置定时器,同时将读事件添加到事件驱动中,等待下一次回调处理。

void ngx_http_init_connection(ngx_connection_t *c)
{
    ...
    // 设置读写事件回调处理方法
    rev = c->read;
    rev->handler = ngx_http_wait_request_handler;
    c->write->handler = ngx_http_empty_handler;

    if( rev->ready ) {
        if( ngx_use_accept_mutex ) {
            ngx_post_event(rev, &ngx_posted_events);
            return;
        }
        // 事件已经准备好, 直接处理
        rev->handler(rev);
        return;
    }

    // 设置定时器
    ngx_add_timer(rev, c->listening->post_accept_timeout);
    ngx_reusable_connection(c, 1);

    // 将读事件加入事件驱动中
    if(ngx_handle_read_event(rev, 0) != NGX_OK) {
        ngx_http_close_connection(c);
        return;
    }
}

3. 首次可读事件的处理

当连接对应的套接字缓冲区首次接收到用户的请求数据后,会回调ngx_http_wait_request_handler方法,在该函数中,会调用recv接收用户的请求数据,同时创建一个ngx_http_request_t用于本次http请求处理,然后调用ngx_http_process_request_line开始处理http请求行。

static void ngx_http_wait_request_handler(ngx_event_t *rev)
{
    ....
    // 接收数据
    n = c->recv(c, b->last, size);
    if( n == NGX_AGAIN ) {
        if(!rev->timer_set) {
            ngx_add_timer(rev, c->listening->post_accept_timeout);
            ngx_reusable_connection(c, 1);
        }
        if( ngx_handle_read_event(rev,0) != NGX_OK ) {
            ngx_http_close_connection(c);
            return ;
        }
    }
    if(n == NGX_ERROR ) {
        ngx_http_close_connection(c);
        return ;
    }

    ....
    
    // 创建request
    c->data = ngx_http_create_request(c);
    if(c->data == NULL) {
        ngx_http_close_connection(c);
        return ;
    }
    rev->handler = ngx_http_process_request_line;
    ngx_http_post_request_line(rev);
}

4. http请求行/http头部的接收处理

在完成了请求的初始化后,会依次调用ngx_http_process_request_line和ngx_http_process_request_headers方法开始接收http请求行和http头部,并解析出URL,请求方法等各字段的含义。当这些都处理完成后,调用ngx_http_process_request进入请求真正的处理阶段。

static void ngx_http_process_request_line(ngx_event_t * rev)
{
    ....
    for( ;; ) {
        // 解析 http行
        rc = ngx_http_parse_request_line(r, r->header_in);
        if( rc == NGX_OK ) {
            // 处理http uri
            if(ngx_http_process_request_uri(r) != NGX_OK) {
                return ;
            }

            // 设置连接的读事件回调处理, 并开始处理http请求的头部
            rev->handler = ngx_http_process_request_headers;
            ngx_http_process_request_headers(rev);
            return ;
        }
    }
}

static void ngx_http_process_request_headers(ngx_event_t * rev)
{
    ....
    rc = NGX_AGAIN;
    for( ;; ) {
        if( rc == NGX_AGAIN ) {
            n = ngx_http_request_header(r);
        }

        // 解析http的头部
        rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers);
        if( rc == NGX_HTTP_PARSE_HEADER_DONE) {
            r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
            // 处理http的头部
            rc = ngx_http_process_request_header(r);
            if(rc != NGX_OK) {
                return ;
            }
            // 开始http请求的处理
            ngx_http_process_request(r);
            return ;
        }
    }
}

5. http请求的处理

在ngx_http_process_request中,将连接读写事件的回调处理均设置为ngx_http_request_handler方法,然后调用ngx_http_handler,而在ngx_http_handler中最终调用ngx_http_core_run_phases开始http的多阶段处理。

void ngx_http_process_request(ngx_http_request_t *r )
{
    ....
    c->read->handler = ngx_http_request_handler;
    c->write->handler = ngx_http_request_handler;
    c->read_event_handler = ngx_http_block_reading;
    ngx_http_handler(r);
    ngx_http_run_posted_requests(c);
}

void ngx_http_handler(ngx_http_request_t * r)
{
    ...
    // 开始http请求的多阶段处理
    r->write_event_handler = ngx_http_core_run_phases;
    ngx_http_core_run_phases(r);
}

6. 发送http请求响应

http请求响应回复一般会通过ngx_http_send_header发送http头部,通过ngx_http_output_filter发送http的包体。ngx_http_send_header和ngx_http_output_filter都是由一系列的filter模块组成,这些模块对响应数据进行加工处理,最终调用ngx_http_write_filter进行数据的发送。

ngx_int_t ngx_http_send_header(ngx_http_request_t *r)
{
    ....
    return ngx_http_top_header_filter(r);
}

ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ....
    rc = ngx_http_top_body_filter(r, in);
    ....
}

7. 结束http请求

一般来讲,结束http请求会调用ngx_http_finalize_request来完成。到这里,整个http的处理流程结束。

© 著作权归作者所有

共有 人打赏支持
hncscwc
粉丝 66
博文 70
码字总数 76137
作品 0
杭州
程序员
加载中

评论(2)

hncscwc
hncscwc

引用来自“摩云飞”的评论

改行专攻nginx了?
有个项目需要,就研究下
摩云飞
摩云飞
改行专攻nginx了?
nginx源码分析—启动流程

作者:阿波 本文链接:http://blog.csdn.net/livelylittlefish/article/details/7243718 Content 0. 序 1. main()分析 2. 注意问题 2.1 几个初值 2.2 nginx工作模式 2.3 一些配置 2.4 其他开...

晨曦之光
2012/03/09
1K
0
nginx源码分析——模块

模块介绍 高度模块化的设计是nginx的架构基础。在nginx中,除了少量的核心代码,其他一切皆为模块。这种模块化设计同时具有以下几个特点: 高度抽象的模块接口 所有的模块都遵循着同样的 ng...

hncscwc
2016/06/17
120
0
nginx源码分析——配置

配置介绍 nginx的配置由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,这些配置文件全部位于nginx安装目录下的conf目录中。 主配置文件nginx.conf中的内容大概是...

hncscwc
2016/06/13
194
0
nginx源码分析——http多阶段处理

多阶段处理概述 nginx将一个http请求分为顺序的多个处理阶段,前一个阶段的结果会影响后一个阶段的处理。例如,ngxhttpaccess_module模块根据IP信息拒绝一个用户请求后,本应接着执行的其他H...

hncscwc
2016/07/04
252
0
nginx源码分析——事件模块

事件模块概述 事件处理框架所要解决的问题是如何收集,管理,分发事件。这里所说的事件,主要以网络事件和定时器事件为主,而网络事件中又以TCP网络事件为主。由于网络事件与网卡中断处理程序...

hncscwc
2016/06/23
186
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

困扰当前数据中心管理的三大难题

导读 当企业发展到一定程度,或者之前的机房不能满足现在的数据中心使用时,企业会对数据中心进行迁移。那么在数据中心进行迁移的时候会遇到哪些风险呢?针对这些风险我们应该做出怎样的措施来...

问题终结者
11分钟前
0
0
设计模式:工厂方法模式(工厂模式)

工厂方法模式才是真正的工厂模式,前面讲到的静态工厂模式实际上不能说是一种真正意义上的设计模式,只是一种变成习惯。 工厂方法的类图: 这里面涉及到四个种类: 1、抽象产品: Product 2、...

京一
27分钟前
0
0
区块链和数据库,技术到底有何区别?

关于数据库和区块链,总会有很多的困惑。区块链其实是一种数据库,因为他是数字账本,并且在区块的数据结构上存储信息。数据库中存储信息的结构被称为表格。但是,区块链是数据库,数据库可不...

HiBlock
34分钟前
0
0
react native 开发碰到的问题

react-navigation v2 问题 问题: static navigationOptions = ({navigation, navigationOptions}) => ({ headerTitle: ( <Text style={{color:"#fff"}}>我的</Text> ), headerRight: ( <View......

罗培海
41分钟前
0
0
Mac Docker安装流程

久仰Docker大名已久,于是今天趁着有空,尝试了一下Docker 先是从docker的官网上下载下来mac版本的docker安装包,安装很简易,就直接拖图标就好了。 https://www.docker.com/products/docker...

writeademo
49分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部