• HTTP 处理数据包, 有的业务不需要,此时只需要将数据包文读取后丢弃, 但是ngx 为什么还要提供一个丢弃接口呢???解决了什么问题??
  • ------对于HTTP模块而言,放弃接收包体就是简单地不处理包体了,可是对于HTTP框架而言,并不是不接收包体就可以的。因为对于客户端而言,通常
    会调用一些阻塞的发送方法来发送包体,如果HTTP框架一直不接收包体,会导致实现上不够健壮的客户端认为服务器超时无响应,因而简单地关
    闭连接,可这时Nginx模块可能还在处理这个连接。因此,HTTP模块中的放弃接收包体,对HTTP框架而言就是接收包体,但是接收后不做保存,直接丢弃。

    HTTP模块调用的ngx_http_discard_request_body方法用于第一次启动丢弃包体动作,而ngx_http_discarded_request_body_handler是作为请
    求的read_event_handler方法的,在有新的可读事件时会调用它处理包体。ngx_http_read discarded_request_body方法则是根据上述两个方法
    通用部分提取出的公共方法,用来读取包体且不做任何处理。
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
ssize_t size;
ngx_int_t rc;
ngx_event_t *rev; #if (NGX_HTTP_V2)
if (r->stream && r == r->main) {
r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
return NGX_OK;
}
#endif /*
首先检查当前请求是一个子请求还是原始请求。为什么要检查这个呢?因为对于子请求而言,它不是来自客户端的请求,所以不存在处理HTTP
请求包体的概念。如果当前请求是原始请求,则继续执行;如果它是子请求,则直接返回NGX_OK表示丢弃包体成功。检查ngx_http_request_t结构
体的request_body成员,如果它已经被赋值过且不再为NULL空指针,则说明已经接收过包体了,这时也需要返回NGX_OK表示成功。
*/
if (r != r->main || r->discard_body || r->request_body) {
return NGX_OK;
} if (ngx_http_test_expect(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
} rev = r->connection->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body"); /*
检查请求连接上的读事件是否在定时器中,这是因为丢弃包体不用考虑超时问题(linger_timer例外,本章不考虑此情况)。如果读事件
的timer set标志位为1,则从定时器中移除此事件。还要检查content-length头部,如果它的值小于或等于0,同样意味着可以直接返回
NGX一OK,表示成功丢弃了全部包体。
*/
if (rev->timer_set) {
ngx_del_timer(rev, NGX_FUNC_LINE);
}
if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
return NGX_OK;
} size = r->header_in->last - r->header_in->pos; if (size || r->headers_in.chunked) {
rc = ngx_http_discard_request_body_filter(r, r->header_in); if (rc != NGX_OK) {
return rc;
} if (r->headers_in.content_length_n == 0) {
return NGX_OK;
}
} /*
在接收HTTP头部时,还是要检查是否凑巧已经接收到完整的包体(如果包体很小,那么这是非常可能发生的事),如果已经接收到完整的包
体,则直接返回NGX OK,表示丢弃包体成功,否则,说明需要多次的调度才能完成丢弃包体这一动作,此时把请求的read_event_handler
成员设置为ngx_http_discarded_request_body_handler方法。
*/
rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) {
/* 返回NGX一OK表示已经接收到完整的包体了,这时将请求的lingering_close延时关闭标志位设为0,表示不需要为了包体的接收而
延时关闭了,同时返回NGX—OK表示丢弃包体成功。 */
r->lingering_close = 0;
return NGX_OK;
} if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
} //返回非NGX_OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作 /* rc == NGX_AGAIN */ r->read_event_handler = ngx_http_discarded_request_body_handler; //下次读事件到来时通过ngx_http_request_handler来调用
/* 有可能执行了ngx_http_block_reading->ngx_http_block_reading,所以如果需要继续读取客户端请求,需要add event */
if (ngx_handle_read_event(rev, 0, NGX_FUNC_LINE) != NGX_OK) { //调用ngx_handle_read_event方法把读事件添加到epoll中handle为ngx_http_request_handler
return NGX_HTTP_INTERNAL_SERVER_ERROR;
} /*
返回非NGX_OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作,于是先把引用计数加1,防止这边还在丢弃包体,
而其他事件却已让请求意外销毁,引发严重错误。同时把ngx_http_request_t结构体的discard_body标志位置为1,表示正在丢弃包体,并
返回NGX_OK,当然,达时的NGX_OK绝不表示已经成功地接收完包体,只是说明ngx_http_discard_request_body执行完毕而已。
*/
r->count++;
r->discard_body = 1; return NGX_OK;
}

  HTTP模块调用的ngx_http_discard_request_body方法用于第一次启动丢弃包体动作,而ngx_http_discarded_request_body_handler是作为请
求的read_event_handler方法的,在有新的可读事件时会调用它处理包体。ngx_http_read_discarded_request_body方法则是根据上述两个方法
通用部分提取出的公共方法,用来读取包体且不做任何处理。

void
ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_msec_t timer;
ngx_event_t *rev;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf; c = r->connection;
rev = c->read; //首先检查TCP连接上的读事件的timedout标志位,为1时表示已经超时,这时调用ngx_http_finalize_request方法结束请求,传递的参数是NGX_ERROR,流程结束
if (rev->timedout) {
c->timedout = 1;
c->error = 1;
ngx_http_finalize_request(r, NGX_ERROR);
return;
} if (r->lingering_time) {
timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); if ((ngx_msec_int_t) timer <= 0) {
r->discard_body = 0;
r->lingering_close = 0;
ngx_http_finalize_request(r, NGX_ERROR);
return;
} } else {
timer = 0;
} //调用ngx_http_read_discarded_request_body方法接收包体,检测其返回值。
rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) {
r->discard_body = 0;
r->lingering_close = 0;
ngx_http_finalize_request(r, NGX_DONE);
return;
} if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
c->error = 1;
ngx_http_finalize_request(r, NGX_ERROR);
return;
} /* rc == NGX_AGAIN */ if (ngx_handle_read_event(rev, 0, NGX_FUNC_LINE) != NGX_OK) {
c->error = 1;
ngx_http_finalize_request(r, NGX_ERROR);
return;
} if (timer) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); timer *= 1000; if (timer > clcf->lingering_timeout) {
timer = clcf->lingering_timeout;
} ngx_add_timer(rev, timer, NGX_FUNC_LINE);
}
}
*/ //ngx_http_read_discarded_request_body方法与ngx_http_do_read_client_request_body方法很类似
static ngx_int_t
ngx_http_read_discarded_request_body(ngx_http_request_t *r)
{
size_t size;
ssize_t n;
ngx_int_t rc;
ngx_buf_t b;
u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http read discarded body"); ngx_memzero(&b, sizeof(ngx_buf_t)); b.temporary = 1; for ( ;; ) {
/*
丢弃包体时请求的request_body成员实际上是NULL室指针,那么用什么变量来表示已经丢弃的包体有多大呢?实际上这时使用
了请求ngx_http_request_t结构体headers_in成员里的content_length_n,最初它等于content-length头部,而每丢弃一部分包体,就会在
content_length_n变量中减去相应的大小。因此,content_length_n表示还需要丢弃的包体长度,这里首先检查请求的content_length_n成员,
如果它已经等于0,则表示已经接收到完整的包体,这时要把read event_handler重置为ngx_http_block_reading方法,表示如果再有可读
事件被触发时,不做任何处理。同时返回NGX_OK,告诉上层的方法已经丢弃了所有包体。
*/
if (r->headers_in.content_length_n == 0) {
r->read_event_handler = ngx_http_block_reading;
return NGX_OK;
} /* 如果连接套接字的缓冲区上没有可读内容,则直接返回NGX_AGAIN,告诉上层方法需要等待读事件的触发,等待Nginx框架的再次调度。 */
if (!r->connection->read->ready) {
return NGX_AGAIN;
} size = (size_t) ngx_min(r->headers_in.content_length_n,
NGX_HTTP_DISCARD_BUFFER_SIZE); n = r->connection->recv(r->connection, buffer, size); if (n == NGX_ERROR) {
r->connection->error = 1;
return NGX_OK;
} if (n == NGX_AGAIN) { //如果套接字缓冲区中没有读取到内容
return NGX_AGAIN;
} if (n == 0) { //如果客户端主动关闭了连接
return NGX_OK;
} b.pos = buffer;
b.last = buffer + n; //接收到包体后,要更新请求的content_length_n成员,从而判断是否读取完毕,如果为0表示读取完毕,同时继续循环
rc = ngx_http_discard_request_body_filter(r, &b); if (rc != NGX_OK) {
return rc;
}
}
}

http 请求体数据处理2--ngx的更多相关文章

  1. post请求体过大导致ngx.req.get_post_args()取不到参数体的问题

    http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size 该地址对于client_body_buf ...

  2. http 请求体数据--ngx

    HTTP包体的长度有可能非常大,不同业务可能对包体读取 处理不相同, 比如waf, 也许会读取body内容或者只是读取很少的前几十字节.所以根据不同业务特性,对http body 数据包处理方式不同, ...

  3. iOS开发——网络篇——文件下载(NSMutableData、NSFileHandle、NSOutputStream)和上传、压缩和解压(三方框架ZipArchive),请求头和请求体格式,断点续传Range

    一.小文件下载 NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion ...

  4. nginx请求体读取(二)

    2,丢弃请求体 一个模块想要主动的丢弃客户端发过的请求体,可以调用nginx核心提供的ngx_http_discard_request_body()接口,主动丢弃的原因可能有很多种,如模块的业务逻辑压 ...

  5. nginx请求体读取

    上节说到nginx核心本身不会主动读取请求体,这个工作是交给请求处理阶段的模块来做,但是nginx核心提供了ngx_http_read_client_request_body()接口来读取请求体,另外 ...

  6. 通过 Spring RestTemplate 调用带请求体的 Delete 方法(Delete With Request Body)

    Spring 框架的RestTemplate 类定义了一些我们在通过 java 代码调用 Rest 服务时经常需要用到的方法,使得我们通过 java 调用 rest 服务时更加方便.简单.但是 Res ...

  7. elasticsearch(5) 请求体搜索

    上一篇提到的轻量搜索非常简单便捷,但是通过请求体查询可以更充分的利用查询的强大功能.因为_search api中大部分参数是通过HTTP请求体而非查询字符串来传递的. 一 空查询 对于空查询来说,最简 ...

  8. 获取【请求体】数据的3种方式(精)(文末代码) request.getInputStream() request.getInputStream() request.getReader()

    application/x- www-form-urlencoded是Post请求默认的请求体内容类型,也是form表单默认的类型.Servlet API规范中对该类型的请求内容提供了request. ...

  9. 从Excel获取请求体

    Excel文件 .py文件---------------------- import xlrdimport re def fetch_body(path,sheet,name,adict):     ...

随机推荐

  1. css实现中间横线俩边文字效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. React Ref 其实是这样的

    大家好,我是Mokou,好久没有冒泡了,最近一直在看研究算法和数据结构方面的东西,但是似乎很多前端不喜欢看这种东西,而且目前本人算法方面也很挫,就不献丑了. 当然了,最近也开始研究React了,这篇文 ...

  3. 网页添加 Live2D 看板娘

        我是先参考别人的[点击跳转]博客来做的.不过我发现网上很多人都没有把一些细节写出来,用了别人那里下载的文件后里面的一些跳转链接就跳到他们的页面了.所以我这里写一写如何修改这些跳转链接吧. 1. ...

  4. kafka-伪集群搭建

      一.简介 Apache Kafka是一个快速.可扩展的.高吞吐的.可容错的分布式"发布-订阅"消息系统,使用Scala与Java语言编写,能够将消息从一个端点传递到另一个端点, ...

  5. Linux命令获得帮助

    在Linux中获得帮助 查帮助的思路 whatis CMD mandb type CMD 如果内部:help CMD ; man bash 如果外部:CMD --help | -h 概述 获取帮助的能 ...

  6. 使用TLSharp进行Telegram中遭遇循环体内报session.dat文件被占用时解决方式一例

    背景 公司做Telegram开发,.net Framework项目,调用TLSharp作为框架进行开发. 开发需求是读取群里新到达的信息并进行过滤. 由此不可避免得要用到 TLSharp.Core.T ...

  7. 异常java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

    通过HttpServletResponse的addCookie(Cookie cookie)向客户端写cookie信息,这里使用的tomcat版本是8.5.31,出现如下报错: java.lang.I ...

  8. Bitmap缩放(一)

    使用矩阵进行压缩,通过缩放图片尺寸,来达到压缩图片的效果,和采样率的原理一样.先用位图的option将位图压缩一半,再用matrix缩放0.3f public class MainActivity e ...

  9. bash xshell 特性

    1.tab键补全 2.命令行常用快捷键: ctrl键+ c    #取消当前操作 ctrl键+ d    #退出当前用户登录 ctrl键+ a    #光标移动到光标所在行的行首 ctrl键+ e  ...

  10. Ace editor中文文档

    介绍 Ace是一个用JavaScript编写的可嵌入代码编辑器.它与Sublime,Vim和TextMate等本地编辑器的功能和性能相匹配.它可以轻松地嵌入任何网页和JavaScript应用程序中. ...