nginx模块:捕获整个响应体

时间:2014-05-15 13:29:43

标签: nginx filter module buffer

虽然Nginx是一款非常有趣的软件,但缺乏文档却让我发疯。

目标:捕获整个响应正文,该正文将记录在服务器上。

问题:我总是有一个大小为ZERO的缓冲区。

方法

我希望能够使用body filter来完成此要求,在迭代完整缓冲区链之前会等待last_buf

/**
 * @param   ngx_http_request_t     *r     HTTP request
 * @param   ngx_chain_t            *in    Buffer chain
 */
static ngx_int_t
create_response_snapshot(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_chain_t *chain = NULL;
    int chain_contains_last_buffer = 0;
    size_t buffer_size = 0;

    // check if body is complete
    chain = in;
    for ( ; ; )
    {
        if (chain->buf->last_buf)
        {
            chain_contains_last_buffer = 1;
        }

        if (NULL == chain->next)
            break;

        chain = chain->next;
    }

    if (0 == chain_contains_last_buffer)
    {
        // response is not complete
        return ngx_http_next_body_filter(r, in);
    }

    // Response Content-Length
    ngx_log_error(NGX_LOG_ALERT,r->connection->log,0,"Content-Length: %d",
                  r->headers_out.content_length_n);

    // lets iterate buffers chain
    for (chain = in; NULL != chain; chain = chain->next)
    {
        buffer_size = ngx_buf_size(chain->buf);
        ngx_log_error(NGX_LOG_ALERT,r->connection->log,0,"buffer_size#%d",buffer_size);
    }

    return ngx_http_next_body_filter(r, in);
}

1 个答案:

答案 0 :(得分:2)

我的评论太大而无法发表评论,但我觉得这不是一个正确的答案 - 哦,好吧。

要重新迭代,您发布的代码的问题是您的模块的主体过滤器功能不会立即在整个链上被调用。在第一件,然后是第二件,它被调用,直到nth件。最后,它被一个完全空链调用,无论出于什么原因,last_buf = 1的buf总是自己为空。

所以我认为你想要做的是通过在模块中累积缓冲区来“阻止”缓冲区流,而不会释放任何缓冲区,直到你同时拥有所有缓冲区。

查看替换过滤器模块:http://lxr.nginx.org/source//src/http/modules/ngx_http_sub_filter_module.c

它使用了我所指的“忙”链。从我能够告诉它使用它来跟踪实际发送的缓冲区(当发生这种情况时,将大小设置为零)并将这些缓冲区添加到模块上下文的空闲列表中以供重用。有关此行为,请参阅第438行的ngx_http_sub_output。

我的建议是做一些类似于该模块的操作,除非在你拥有整个页面之前没有调用下一个过滤器。如果要整个处理整个页面,则无法调用next_filter,因为这样做会导致数据被发送到客户端。这又与Nginx的设计背道而驰,所以我认为如果可以的话,你应该找到一个不需要整个响应体的替代方案。