nginx http框架执行流程(6) - 接收请求体

2018-07-29 13:45:33

如果请求体对我们有用比如一般的 POST 请求,那么就该接收保存请求体,nginx 对外提供了了 ngx_http_read_client_request_body() 函数,它的第2个参数为请求体接收完成后的回调函数,它的原型如下

ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,
    ngx_http_client_body_handler_pt post_handler);

我们先来看下比较关键的 ngx_http_request_body_t 结构体。

// 请求体的处理函数
typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);

// 请求体的数据结构,用于读取或丢弃请求体数据
typedef struct {
    ngx_temp_file_t                  *temp_file;

    // 收到的数据都存在这个链表里
    // 可以是内存也可以是临时文件
    // 最后一个节点b->last_buf = 1
    ngx_chain_t                      *bufs;

    // 当前使用的缓冲区
    ngx_buf_t                        *buf;

    // 剩余要读取的字节数
    // 对于确定长度(有content length)的就是r->headers_in.content_length_n
    // 在读取过程中会不断变化,最终为0
    off_t                             rest;

    off_t                             received;

    // 空闲节点链表,优化用,避免再向内存池要节点
    ngx_chain_t                      *free;

    ngx_chain_t                      *busy;

    // 读取chunk数据的结构体,用于ngx_http_parse_chunked()
    ngx_http_chunked_t               *chunked;

    // 当读取完毕后的回调函数
    // 即ngx_http_read_client_request_body的第二个参数
    ngx_http_client_body_handler_pt   post_handler;
} ngx_http_request_body_t;

相关的2个配置指令如下,详细请参考 核心配置指令

client_body_buffer_size 请求体缓冲区大小默认为8K,理论上超过了8k就会存入临时文件。

client_body_in_file_only 请求体只存放在临时文件,默认为关闭。

默认情况下,当请求体超过了 client_body_buffer_size 配置的大小,那么会被存入临时文件,那么 上面的  temp_file 指针就为非 NULL。

从下面的源码可以看出,其实在非 chunk 请求中,请求体大小在 10240 以内的都会直接存在内存里而不会存临时文件。而如果请求体大小超过了 10240,那么会以一次只接收 8192 字节去接收请求体并存入临时文件。 

    // 查看body的缓冲区大小
    size = clcf->client_body_buffer_size;

    // 增加1/4的长度
    size += size >> 2;

    // 长度确定,且在size里可以容纳剩余字节数
    if (!r->headers_in.chunked && rb->rest < size) {
        size = (ssize_t) rb->rest;

    } else {
        size = clcf->client_body_buffer_size;
    }

当请求体读取完毕时,会回调 ngx_http_read_client_request_body() 指定的 post_handler 回调函数,此时如果接收的请求体是存在于临时文件里。

r->request_body->temp_file != NULL;

并且通常情况下

r->request_body->bufs->buf->file

//等价于

r->request_body->temp_file->file

r->request_body->temp_file 通常是用来判断是否用临时文件来存储请求体,而我们取数据一般会从 r->request_body->bufs 里取。

由于读取请求体中间逻辑很复杂,这里不深究,只附上2张流程图。

下面为 ngx_http_read_client_request_body() 方法的流程图

ngx_http_do_read_client_request_body() 方法的流程图


备注

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


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