在解析完  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. 8.Android-简单的登录案例编写

    本章来学习登录案例,由于还未学习自定义控件外观,所以ui界面先用最简单的,并保存登录账号密码到data/data/包名/files下 1.学习之前需要掌握的Context类(通过Context来往AP ...

  2. Oracle误操作 数据恢复

    SELECT * FROM v$sqlarea //查询最近sql记录 SELECT r.FIRST_LOAD_TIME,r.* FROM v$sqlarea r ORDER BY r.FIRST_L ...

  3. reids等非关系数据库管理工具treesoft

    先下载treesoft 链接:https://pan.baidu.com/s/1o8UPK7lF0-WvE9afoR0sWw 提取码:3uc3 下载好之后进行解压文件 解压完成后目录结构 将webap ...

  4. 多测师讲解自动化测试 _RF分配id_高级讲师肖sir

    1.Assign Id To Element.

  5. WebFlux快速上手

    一.新建项目 示例使用IDEA快速创建基于SpringBoot的工程. springboot 2.3.1 java 8 WebFlux 必须选用Reactive的库 POM 依赖 <depend ...

  6. spring boot: 设计接口站api的版本号,支持次版本号(spring boot 2.3.2)

    一,为什么接口站的api要使用版本号? 1,当服务端接口的功能发生改进后, 客户端如果不更新版本,    则服务端返回的功能可能不能使用,    所以在服务端功能升级后,     客户端也要相应的使用 ...

  7. centos8使用systemd/systemctl管理系统/服务

    一,systemd的用途? Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置 Systemd 的优点是功能强大,使用方便, 缺点是体系庞大,非常复杂 在cent ...

  8. ansible使用setup模块查看受控机的信息(ansible2.9.5)

    一,ansible的setup模块的用途: 用来获取主机的信息 说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest 对应的 ...

  9. selenium自动登陆

    import osfrom selenium import webdriverimport time,jsonclass Cookie(object): def __init__(self,drive ...

  10. 自动化遍历-appcrawler

    下载appclawler 下载地址:https://pan.baidu.com/s/1dE0JDCH#list/path=%2F 查看帮助文档: java -jar appcrawler-2.4.0- ...