Nginx gzip 过滤器不适用于我的自定义处理程序

Posted

技术标签:

【中文标题】Nginx gzip 过滤器不适用于我的自定义处理程序【英文标题】:Nginx gzip filter not work with my custom handler 【发布时间】:2011-12-08 07:19:01 【问题描述】:

我写了一个非常简单的 nginx 处理程序,只输出一些文本(大小 100B 到 10KB)。

代码在 nginx(ver 1.0.6) 下正常工作

但我发现 gzip 过滤器无法与处理程序一起使用。

当我在 nginx.conf(在 http 部分)中打开 gzip 时,gzip 可以使用静态 html 文件。

但是,处理程序的响应没有使用 gzip 压缩。

经过大量搜索工作,我仍然找不到答案。

任何厘米?多谢。 :-)

//my code :
static ngx_int_t ngx_http_test_handler(ngx_http_request_t *r)

    ngx_chain_t out;
    ngx_buf_t *b;

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    ......
    //writing text to buffer
    ......
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = len;
    r->headers_out.content_type.len = sizeof("text/html")-1;
    r->headers_out.content_type.data = (u_char *) "text/html";

    out.buf = b;
    out.next = NULL;
    return ngx_http_output_filter(r, &out);

【问题讨论】:

【参考方案1】:

如果还不算太晚,我的过滤器模块也遇到了同样的问题。

问题与您更改响应内容类型有关。 Gzip 检查 content_type_len 和 content_type_lowcase 上的 Content-Type 以确定是否必须对响应进行 Gzip 压缩。这段代码应该可以工作:

r->headers_out.content_type_len = strlen("text/html");
r->headers_out.content_type.len = strlen("text/html");
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.content_type_lowcase = NULL;

要了解此代码为何有效,您必须考虑 Gzip 过滤器首先调用方法 ngx_http_test_content_type 以在响应中启用 gzip。您可以在这里查看源代码:http://lxr.evanmiller.org/http/source/http/ngx_http_core_module.c#L1659

【讨论】:

【参考方案2】:

首先你在哪里给ngx_http_send_header(r);打电话?

你在初始化ngx_buf_t *b的成员吗?

您的请求集的内容编码是否?

您的处理程序是否产生错误?如果是这样,不会调用过滤器?

当您的处理程序调用时,需要满足以确保 gzip 过滤器运行(而不是被绕过)的其他约束包括

Gzip 必须在 nginx 配置文件中启用,见here 发送的标头状态应该是 NGX_HTTP_OK、NGX_HTTP_FORBIDDEN 或 NGX_HTTP_NOT_FOUND 应设置内容编码(ngx_table_elt_t* 必须存在,并且其中的值应具有非零长度 content_length_n 应该是有效的(不是-1)并且应该大于或等于配置文件中指定的 gzip_min_length 值 ngx_http_test_content_type 需要返回非空值,例如有效的上下文类型 请求需要有标头和正文

有关 Nginx 模块、Fillter 和 Handler 开发的更多信息,请参阅 here。

【讨论】:

【参考方案3】:

上面的答案似乎……不准确。

检查这一点的代码位于src/http/modules/ngx_http_gzip_filter_module.c 的第 250 行或附近,内容如下:

if (!conf->enable
    || (r->headers_out.status != NGX_HTTP_OK
        && r->headers_out.status != NGX_HTTP_FORBIDDEN
        && r->headers_out.status != 207
        && r->headers_out.status != NGX_HTTP_NOT_FOUND)
    || (r->headers_out.content_encoding
        && r->headers_out.content_encoding->value.len)
    || (r->headers_out.content_length_n != -1
        && r->headers_out.content_length_n < conf->min_length)
    || ngx_http_test_content_type(r, &conf->types) == NULL
    || r->header_only)

    return ngx_http_next_header_filter(r); <-- this is the line you want to breakpoint!

如果我没看错,条件是:

HTTP 状态必须为 200、403 或 404。 content_encoding 必须设置(这是有道理的:gzipping 将内容编码设置为“gzip”) content_length_n,如果设置,必须大于最小长度(默认 20)。不设置内容长度是可以接受的。 content_type 必须在有效列表中。默认情况下,只接受“text/html”,但可以使用gzip_types 配置选项设置其他类型。如果列表中包含“*”,则任何内容类型(包括完全没有)都可以。 一定要压缩一些实体

从 1.7.10 版开始,上面的 return 位于第 257 行。设置“关闭守护程序”,在 gdb 和 b ngx_http_gzip_filter_module.c:257 下运行将允许您准确查看检查失败的时间和方式。 (如果你正在尝试这个,你可能应该从源代码编译......)

【讨论】:

以上是关于Nginx gzip 过滤器不适用于我的自定义处理程序的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的容器注册表适用于 gitlab 自动部署,但不适用于我的自定义管道?

Pyqt5 鼠标事件不适用于我的自定义标签栏

<ReferenceArrayInput /> 不适用于我的自定义数据提供程序(棱镜)

HTTPS 不适用于 Amazon Cloudfront 中的自定义域

过滤和分页不适用于 ngxpagination 模板

Bold / Italic不适用于使用PhantomJS的自定义字体