0
点赞
收藏
分享

微信扫一扫

http 响应 ngx_http_send_header ngx_http_output_filter

  在解析完  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_响应头

 


 

 

http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子

举报

相关推荐

0 条评论