在解析完  http 请求报文后, 需要发出响应报文, 那么ngx 框架 提供了那些通用接口呢?如果自己设计将所用的模块的响应接口合并起来 你会怎么设计呢??

  响应头过滤函数主要的用处就是处理HTTP响应的头,可以根据实际情况对于响应头进行修改或者添加删除。

响应头过滤函数先于响应体过滤函数,而且只调用一次,所以一般可作过滤模块的初始化工作。

响应头过滤函数的入口只有一个:该函数向客户端发送回复的时候调用,然后按前一节所述的执行顺序。该函数的返回值一般是NGX_OK,NGX_ERROR和NGX_AGAIN,分别表示处理成功,失败和未完成。

//调用ngx_http_output_filter方法即可向客户端发送HTTP响应包体,ngx_http_send_header发送响应行和响应头部
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
{
if (r->post_action) {
return NGX_OK;
} ngx_log_debugall(r->connection->log, 0, "ngx http send header");
if (r->header_sent) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"header already sent");
return NGX_ERROR;
} if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
} return ngx_http_top_header_filter(r);
}
/*
当执行ngx_http_send_header发送HTTP头部时,就从ngx_http_top_header_filter指针开始遍历所有的HTTP头部过滤模块,
而在执行ngx_http_output_filter发送HTTP包体时,就从ngx_http_top_body_filter指针开始遍历所有的HTTP包体过滤模块
*/ //包体通过ngx_http_output_filter循环发送 /*
注意对于HTTP过滤模块来说,在ngx_modules数组中的位置越靠后,在实陈执行请求时就越优先执行。因为在初始化HTTP过滤模块时,每一个http
过滤模块都是将自己插入到整个单链表的首部的。
*/ //ngx_http_header_filter_module是最后一个header filter模块(ngx_http_top_header_filter = ngx_http_header_filter;他是最后发送头部的地方),
//ngx_http_write_filter_module是最后一个包体writer模块(ngx_http_top_body_filter = ngx_http_write_filter;),他是最后放包体的地方
//调用ngx_http_output_filter方法即可向客户端发送HTTP响应包体,ngx_http_send_header发送响应行和响应头部
ngx_http_output_header_filter_pt ngx_http_top_header_filter;//所有的HTTP头部过滤模块都添加到该指针上 ngx_http_send_header中调用链表中所有处理方法
//该函数中的所有filter通过ngx_http_output_filter开始执行
ngx_http_output_body_filter_pt ngx_http_top_body_filter;//所有的HTTP包体部分都是添加到该指针中,在ngx_http_output_filter中一次调用链表中的各个函数

  ngx_http_top_header_filter是一个全局变量。当编译进一个filter模块的时候,就被赋值为当前filter模块的处理函数。而ngx_http_next_header_filter是一个局部全局变量,它保存了编译前上一个filter模块的处理函数。所以整体看来,就像用全局变量组成的一条单向链表。

    每个模块想执行下一个过滤函数,只要调用一下ngx_http_next_header_filter这个局部变量。而整个过滤模块链的入口,需要调用ngx_http_top_header_filter这个全局变量。ngx_http_top_body_filter的行为与header fitler类似。

响应头和响应体过滤函数的执行顺序如下所示:

在向headers链表中添加自定义的HTTP头部时,可以参考ngx_list_push的使用方法。这里有一个简单的例子,如下所示。
ngx_table_elt_t* h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
 return NGX_ERROR;
}

h->hash = 1;
h->key.len = sizeof("TestHead") - 1;
h->key.data = (u_char *) "TestHead";
h->value.len = sizeof("TestValue") - 1;
h->value.data = (u_char *) "TestValue";
这样将会在响应中新增一行HTTP头部:
TestHead: TestValud\r\n

响应体过滤函数

  响应体过滤函数是过滤响应主体的函数。ngx_http_top_body_filter这个函数每个请求可能会被执行多次,它的入口函数是ngx_http_output_filter,

当ngx_http_output_filter方法返回时,可能由于TCP连接上的缓冲区还不可写,所以导致ngx_buf_t缓冲区指向的内存还没有发送,可这时方法返回已把控制权交给Nginx了,又会导致栈里的内存被释放,最后就会造成内存越界错误。因此,在发送响应包体时,尽量将ngx_buf_t中的pos指针指向从内存池里分配的内存。

//r是request请求,in是输入的chain
//调用ngx_http_output_filter方法即可向客户端发送HTTP响应包体,ngx_http_send_header发送响应行和响应头部

Nginx还封装了一个生成ngx_buf_t的简便方法,它完全等价于上面的6行语句,如下所示。
ngx_buf_t *b = ngx_create_temp_buf(r->pool, 128);
分配完内存后,可以向这段内存写入数据。当写完数据后,要让b->last指针指向数据的末尾,如果b->last与b->pos相等,那么HTTP框架是不会发送一个字节的包体的。

最后,把上面的ngx_buf_t *b用ngx_chain_t传给ngx_http_output_filter方法就可以发送HTTP响应的包体内容了。例如:
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{//如果内容被保存到了临时文件中,则会在ngx_http_copy_filter->ngx_output_chain->ngx_output_chain_copy_buf->ngx_read_file中读取文件内容,然后发送
ngx_int_t rc;
ngx_connection_t *c; c = r->connection; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http output filter \"%V?%V\"", &r->uri, &r->args); rc = ngx_http_top_body_filter(r, in); //filter上面的最后一个钩子是ngx_http_write_filter if (rc == NGX_ERROR) {
/* NGX_ERROR may be returned by any filter */
c->error = 1;
} return rc;
}

ngx_http_output_filter可以被一般的静态处理模块调用,也有可能是在upstream模块里面被调用,对于整个请求的处理阶段来说,他们处于的用处都是一样的,就是把响应内容过滤,然后发给客户端。

http 响应 ngx_http_send_header ngx_http_output_filter的更多相关文章

  1. http代理阅读3 发送mem处理

    每次客户端有可读数据触发时,优先检测是否还有数据没有发送,如果有则发送数据,然后在读取client数据 //向后端发送请求的调用过程 //ngx_http_upstream_send_request_ ...

  2. 【Nginx】发送响应

    请求处理完毕后,需要向用户发送http响应,告知客户端Nginx的执行结果.http响应主要包括响应行.响应头部.包体三部分.发送http响应时需要执行发送http头部(发送http头部时也会发送响应 ...

  3. http代理阅读4 响应缓存处理

    if (c->read->ready) { ngx_http_upstream_process_header(r, u); //读事件触发 准备处理http头部信息 return; } 向 ...

  4. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

  5. 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的

    我们在<服务器在管道中的"龙头"地位>中对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了介绍,为了让读者朋友们对管道中的服务器具有更 ...

  6. WebApi接口 - 响应输出xml和json

    格式化数据这东西,主要看需要的运用场景,今天和大家分享的是webapi格式化数据,这里面的例子主要是输出json和xml的格式数据,测试用例很接近实际常用情况:希望大家喜欢,也希望各位多多扫码支持和点 ...

  7. 一些关于Linux入侵应急响应的碎碎念

    近半年做了很多应急响应项目,针对黑客入侵.但疲于没有时间来总结一些常用的东西,寄希望用这篇博文分享一些安全工程师在处理应急响应时常见的套路,因为方面众多可能有些杂碎. 个人认为入侵响应的核心无外乎四个 ...

  8. 一步步开发自己的博客 .NET版 剧终篇(6、响应式布局 和 自定义样式)

    前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做 ...

  9. 修改Tomcat响应请求时返回的Server内容

    HTTP Server在响应请求时,会返回服务器的Server信息,比如 Tomcat 7 的Header是: 这东西其实会给一些别有用心之人带来一定的提示作用:为安全起见,我们一般会建议去掉或修改这 ...

随机推荐

  1. .net core中的那些常用的日志框架(Serilog篇)

    前言 上文说到Nlog日志框架,感觉它功能已经很强大,今天给大家介绍一个很不错的日志框架Serilog,根据我的了解,感觉它最大的优势是,结构化日志,它输出的日志是Json的格式,如果你使用的是Mon ...

  2. pandas常用方法总结

    In [49]: frame2 Out[49]: year state pop debt one 2000 Ohio 1.5 NaN two 2001 Ohio 1.7 NaN three 2002 ...

  3. 【C语言】这种求结构体成员大小的方法,你可能需要了解一下~

    在C语言编程中,有时候需要知道某结构体中某成员的大小,比如使用堆内存来存储结构体中的某成员时,需要知道该成员的大小,才好确定所需申请的空间大小.求某结构体中某成员的大小,你会怎么做? 例子: type ...

  4. 【贪心算法】CF Emergency Evacuation

    题目大意 vjudge链接 给你一个车厢和一些人,这些人都坐在座位上,求这些人全部出去的时间最小值. 样例1输入 5 2 71 11 21 32 32 44 45 2 样例1输出 9 样例2输入 50 ...

  5. Redis Hashes 数据类型简述

    Redis Hashes 是我们日常使用中比较高频的 Redis 数据类型,内部使用 Redis 字典结构存储,底层基于哈希表结构实现. 下面从哈希表节点,哈下表结构,Redis 字典,Redis 字 ...

  6. Redis五种常用数据类型

    string 字符串常用操作 1.存入字符串键值对  SET key value 2.批量存储字符串键值对  MSET key value [key value ...] 3.获取一个字符串键值  G ...

  7. GO用内置包写爬虫

    一.要点 爬虫被想太多,把他当做一个模拟别人的请求响应即可了,所有呢go写爬虫关键是写请求 二.get请求 package main import ( "bytes" " ...

  8. JavaWeb宿舍管理系统(附 演示、源码下载地址)

    宿舍管理是高校管理的重要组成部分,一套优秀的管理系统不仅可以降低宿舍管理的难度,也能在一定程度上减少学校管理费用的支出,能是建设现代化高校管理体系的重要标志. 本篇文章将带你从运行环境搭建.系统设计. ...

  9. 深入理解Java注解类型(@Annotation)

    http://blog.csdn.net/javazejian/article/details/71860633  出自[zejian的博客] java注解是在JDK5时引入的新特性,鉴于目前大部分框 ...

  10. 容器之间通讯方式\与pod关系

    1.概述 k8s里面容器是存在于pod里面的,所以容器之间通讯,一般分为三种类型:1. pod内部容器之间 2. pod 与 pod 容器之间 3. pod 访问service服务 (1) pod内部 ...