Nginx丢弃http包体处理实例详解

2019-10-17 18:32:24丽君

         在接收http请求头部时,如果也顺便接收了http包体数据,这个时候就没有必要继续执行剩余的操作,丢弃包体成功,函数直接返回。如果一次调度没有丢弃完所有包体,则会设置http请求结构ngx_http_request_s的读事件read_event_handler为:ngx_http_discarded_request_body_handler, 下一次被调度时由这个函数负责丢弃剩余的包体。因此ngx_http_discard_request_body只会被http模块首次调用。

        函数也会调用实际的丢包函数ngx_http_read_discarded_request_body开始进行接收包体后直接丢弃处理。

二、丢包处理 

       ngx_http_read_discarded_request_body函数负责接收来自客户端的包体数据,然后再丢弃。因此对于模块而言,就是丢弃包体操作,但对于框架而言,丢弃包体操作其实就是接收包体操作, 只不过接收后的包体数据没有交给模块使用而已。为什么框架要接收包体后再直接丢弃呢? 岂不是多此一举。其实不然,之所以这样做是有原因的。假设某个不健壮的客户端浏览器使用阻塞的方法向nginx服务器发送了http包体数据, 如果nginx框架不接收的话,会导致客户端浏览器超时没有反应,从而导致客户端浏览器关闭这个连接。因此nginx的http框架要先从内核中接收来自客户端的包体数据, 但这些数据对于模块而言是没有用的,因此接收后的这些数据会直接被丢弃。

//功能: 从内核中读取数据到nginx中,nginx不对收到的数据进行处理。相当于丢弃包体 
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r) 
{ 
 //用于接收包体的临时缓冲区 
 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; 
 
 for ( ;; ) 
 { 
  //已经全部丢弃成功 
  if (r->headers_in.content_length_n == 0) 
  { 
   //设置丢弃后的读事件回调,再有读事件时,不做任何处理 
   r->read_event_handler = ngx_http_block_reading; 
   return NGX_OK; 
  } 
   
  //从内核中接收包体到临时缓冲区 
  n = r->connection->recv(r->connection, buffer, size); 
 
  //更新剩余需要接收的包体大小 
  r->headers_in.content_length_n -= n; 
 } 
} 

        函数内部只是使用一个临时的缓冲区变量存放每次接收来自内核的包体数据。并没有把这部分数据保存到http请求结构中的request_body缓冲区。因此包体数据没有交给http模块,相当于被丢弃了。在所有包体从内核中接收完成时,设置http请求结构ngx_http_request_s的读事件read_event_handler回调设置为: ngx_http_block_reading, 表示再收到来自客户端的数据,则不进行任何处理了。因为已经接收完所有的包体数据,也就不需要理会来自客户端浏览器的其它数据。