文档章节

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

hncscwc
 hncscwc
发布于 2016/07/15 21:29
字数 992
阅读 398
收藏 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
粉丝 67
博文 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源码分析——http多阶段处理

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

hncscwc
2016/07/04
252
0
nginx源码分析——配置

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

hncscwc
2016/06/13
194
0
nginx源码分析——事件模块

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

hncscwc
2016/06/23
186
0

没有更多内容

加载失败,请刷新页面

加载更多

申请Let's Encrypt永久免费SSL证书

环境安装 1、安装git yum install git-core 2、安装python 系统自带 不用安装 只要版本大于2.7即可。 获取Let's Encrypt免费SSL证书 先停止nginx 在阿里云安全组里加入 443端口的入规则 git ...

HGMrWang
27分钟前
1
0
如何使用playframework进行更好的开发

1: 自定义基类Controller 相信刚开始使用Play的人写的Controller 都继承于 play.mvc.Controller , 但这并不是一个很好的选择,自建基类Controller可以扩展更多的功能。 1.1 验证功能。 后台...

tuerqidi
32分钟前
4
0
解决ubuntu下root用户 不能ftp登陆的问题

解决ubuntu下root用户 不能ftp登陆的问题 一般情况下,由于种种原因ftp是不让root用户远程登陆,但只要你修改以个文件就可以登陆了. 注释掉 /etc/ftpusers 中的root即可 (最后重启vsftpd serv...

15834278076
44分钟前
0
0
《JavaScript高级程序设计(第3版)》阅读笔记

第6章 面向对象的程序设计 6.2 创建对象 6.2.1 工厂模式 JavaScript创建对象(一)—— 工厂模式 6.2.2 构造函数模式 JavaScript创建对象(二)——构造函数模式 6.2.3 原型模式 JavaScript...

Bob2100
48分钟前
1
0
Windows小技巧 – Win+R提高Windows使用效率

追求效率的朋友都需要一款顺手的快速启动工具,Win 平台上有键盘流的RunZ、Listary、ALTRun、Launchy、Wox 和图标流的 Fences、Rolan、 WinLaunch 等,而 Mac 上也有 Alfred、Spotlight。 而...

QQZZFT
51分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部