在上一篇文章中,我们讲解了nginx是如何读取请求行的数据,并且解析请求行的。本文我们则主要讲解nginx是如何读取客户端发送来的请求头的数据,并且解析这些数据的。本质上来讲,请求行的数据和请求头的数据读取流程是基本一致的,因为其都面临着如何从间断的数据流中读取到数据,也面临着如何对数据进行处理的问题。
1. 请求头读取主流程
在介绍请求头的读取流程之前,我们首先展示一个http请求报文的示例:
示例中的第一行数据就是请求行,而后面的几行都是请求头。每一个请求头都是以name: value的格式组装的,并且每一个请求头都占用一行。 在上一篇介绍请求行读取流程的文章中,我们讲到,一旦请求行读取完成,nginx就会将当前读取事件的回调函数修改为ngx_http_process_request_headers()方法,并且直接调用该方法尝试读取请求头数据。这个方法就是读取请求行数据的主流程,如下是该方法的源码:
这里请求头的读取主要分为如下几个步骤:
首先检查当前读取事件是否已经超时,如果超时了,则直接关闭当前连接; 判断是否r->header_in->pos == r->header_in->end成立,这个主要是检查当前读取缓冲区中是否有可以存储新读取的数据的内存空间,如果没有,则从内存池中新申请一块内存空间; 调用ngx_http_read_request_header()方法读取当前连接句柄上的数据,其返回值如果大于0,则表示读取到的数据长度,如果等于0,则表示客户端断开了连接,如果为NGX_ERROR,则表示读取发生了异常,如果为NGX_AGAIN,则此次没有读取到数据,需要继续读取新的数据。可以看到,这里首先判断返回值是否为NGX_AGAIN,是则直接返回,而没有做任何其他的处理,这主要是因为当前的读事件的回调函数还是ngx_http_process_request_headers(),当有新的读事件触发时,其还是会调用到ngx_http_read_request_header()以再次读取到数据。另一方面,在ngx_http_read_request_header()方法中,如果发现返回值为NGX_AGAIN,其会将当前读事件再次添加到事件队列中,并且为当前连接在epoll句柄上注册读事件; 调用ngx_http_parse_header_line()方法解析读取到的请求头数据,需要注意的是,每次调用该方法都只会解析得到一个请求头,不过经过无限for循环和不停的事件触发机制,最终所有的请求头数据都会读取到。 根据ngx_http_parse_header_line()方法的返回值,如果为NGX_OK,则将新读取到的header存储到r->headers_in.headers链表中; 如果ngx_http_parse_header_line()方法的返回值为NGX_HTTP_PARSE_HEADER_DONE,则表示读取所有的header都成功了,此时首先会调用ngx_http_process_request_header()方法检查读取到的header的合法性,然后调用ngx_http_process_request()方法以启动nginx中http模块的11个阶段,这个方法的实现原理我们将会在后面的文章进行讲解。2. 请求头数据的读取
可以看到,对请求头的读取主要有两个方法:ngx_http_read_request_header()和ngx_http_parse_header_line()。这里的第二个方法比较长,但是其逻辑非常的简单,主要就是解析读取到的数据是否能组成一个完整的请求头(name: value的形式,并且占用一行),如果是,则返回NGX_OK,否则返回NGX_AGAIN以期待继续读取数据。对于这个方法,我们这里不进行讲解,读者可自行阅读源码,我们主要讲解ngx_http_read_request_header()方法是如何读取客户端发送来的请求头数据的:
这里请求头数据的读取主要分为如下几个步骤:
判断当前缓冲区中是否存在还未处理的数据,如果存在,则直接返回。存在还未读取的数据的原因主要是在前面读取请求行数据的过程中,可能会读取一部分或者全部的请求头数据,因而这里会做检查; 判断当前读事件是否已经准备就绪,如果已经就绪,则调用c->recv()方法读取当前连接句柄上的数据; 如果当前读事件还未就绪,则将当前的读事件再次添加到事件队列中,并且为当前连接在epoll句柄上注册读事件; 对第二步的返回值进行判断,如果为0,则表示客户端已经断开了连接,如果为NGX_ERROR,则表示读取数据异常了,这两种情况时都会关闭当前连接,并且向客户端返回400状态码。如果返回值NGX_AGAIN,则从事第三步中的步骤,以继续监听读事件。如果返回值大于0,则表示读取成功,而这个大于0的值就表示读取到的数据长度; 更新存储读取数据的缓冲区的指针数据。3. 小结
本文主要对nginx是如何读取并且解析请求头的流程进行了讲解,并且着重讲解了读取数据的主流程代码和读取的详细步骤。
到此这篇关于详解nginx请求头数据读取流程的文章就介绍到这了,更多相关nginx请求头数据读取内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://my.oschina.net/zhangxufeng/blog/3209987