NGINX中使用ngx_http_output_filter()向一个请求发送响应。
| 1 | ngx_int_t | 
其中,r是请求结构体,in为以ngx_chain_t结构链接起来的需要发送的内容。ngx_http_output_filter()会调用ngx_http_top_body_filter()。NGINX采用filter机制对响应进行处理。filter分为header filter和body filter。NGINX分别将两种filter各构建成一个链表。全局变量ngx_http_top_header_filter指向header filter链表的头结点,而全局变量ngx_http_top_body_filter指向body filter链表的头结点。每个filter中用一个变量记录下一个filter,依据情况决定是调用下一个filter,还是直接返回。
body filter链表顺序如下图:
| 1 | 
 | 
header filter链表顺序如图:
| 1 | 
 | 
ngx_http_write_filter()是最后一个被调用的body filter,它进行真正的网络I/O操作,将响应发送给客户端。实际上, ngx_http_header_filter()也是调用ngx_http_write_filter()来发送响应中的headers。
ngx_http_write_filter()的简化流程如下:
- 检查之前是否有错误发生(c->error被置位)。如果有错误发生,则没有必要再进行网络I/O操作,直接返回NGX_ERROR。1 
 2
 3if (c->error) { 
 return NGX_ERROR;
 }
- 计算之前没有发送完成的内容大小并检查是否存在特殊标志。为了优化性能,当没有必要立即发送响应且响应内容大小没有达到设置的阀值时,NGINX可以暂时推迟发送该部分响应。参看:postpone_output指令。flush标志表示需要立即发送响应。recycled表示该buffer需要循环使用,因而需要立即发送以释放该buffer被重新使用。last标志表示该buffer是响应的最后一部分内容,因而也需要立即发送。
| 1 | for (cl = r->out; cl; cl = cl->next) { | 
- 计算本次将发送的内容大小,检查是否存在特殊标志,并将内容链接到r->out上。1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22for (ln = in; ln; ln = ln->next) { 
 cl = ngx_alloc_chain_link(r->pool);
 if (cl == NULL) {
 return NGX_ERROR;
 }
 cl->buf = ln->buf;
 *ll = cl;
 ll = &cl->next;
 ...
 size += ngx_buf_size(cl->buf);
 if (cl->buf->flush || cl->buf->recycled) {
 flush = 1;
 }
 if (cl->buf->last_buf) {
 last = 1;
 }
 }
- 根据情况决定是需要真正进行网络I/O操作, 还是直接返回。1 
 2
 3if (!last && !flush && in && size < (off_t) clcf->postpone_output) { 
 return NGX_OK;
 }
- 真正进行网络I/O操作,发送内容。1 chain = c->send_chain(c, r->out, limit); 
- 回收发送完成内容的buffer和chain结构, 将没有发送完成的内容存入r->out1 
 2
 3
 4
 5
 6
 7for (cl = r->out; cl && cl != chain; /* void */) { 
 ln = cl;
 cl = cl->next;
 ngx_free_chain(r->pool, ln);
 }
 r->out = chain;
- 根据发送是否完成,返回NGX_OK或NGX_AGAIN。此外,1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12if (chain) { 
 c->buffered |= NGX_HTTP_WRITE_BUFFERED;
 return NGX_AGAIN;
 }
 c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
 if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
 return NGX_AGAIN;
 }
 return NGX_OK;ngx_http_write_filter()中也处理了限速发送的逻辑,本文不详述。