• 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

    响应体过滤函数

      响应体过滤函数是过滤响应主体的函数。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模块里面被调用,对于整个请求的处理阶段来说,他们处于的用处都是一样的,就是把响应内容过滤,然后发给客户端。


     

  • 相关阅读:
    wp8模拟器中使用电脑键盘和模拟器的版本解释
    程序员如何正确的评估自己的薪资
    本地资源之绑定页面的标题和增加软件的语言支持
    C#导出数据的EXCEL模板设计
    程序员高效编程的14点建议
    使用StaticResource给控件定义公共的样式和属性来写界面XAML
    程序员什么时候该考虑辞职
    我的第一个wp8小程序
    检测CPU是否支持虚拟化
    所有经历都是一种恩赐
  • 原文地址:https://www.cnblogs.com/codestack/p/13513344.html
Copyright © 2020-2023  润新知