nginx中gzip_types匹配content-type的方式

本站所有内容来自互联网收集,仅供学习和交流,请勿用于商业用途。如有侵权、不妥之处,请第一时间联系我们删除!Q群:迪思分享

免费资源网 – https://freexyz.cn/

1.背景

我们系统中有一个功能,可以配置content-type类型来决定是否打开gzip压缩。

这个配置与nginx官方的gzip_type不同的地方在于,nginx官方的是写死在配置文件中的,所有请求都生效;我们自研的是,不同用户的gzip_type可以不同。

最近发现一个问题

content-type配置为:image/jpeg,但是后端响应的Content-Type为”

image/jped;charset:UTF-8″时,由于代码中是将配置的content-type与响应头中字符串作精确比较,因此,上述场景,并不能正确打开gzip功能。

nginx对此是如何处理的呢?

后端响应的Content-Type保持为image/jped;charset:UTF-8。

1、配置gzip_type 如下,gzip生效:

gzip_type image/jpeg;

2、配置gzip_type如下,gzip不生效:(nginx官方文档中也没有提及下面的配置方法)

gzip_type “image/jpeg;charset:UTF-8”;

2.nginx处理流程

在进行header_filter时,对content-Type做了校验:

static ngx_int_t ngx_http_gzip_header_filter(ngx_http_request_t *r) { ngx_table_elt_t *h; ngx_http_gzip_ctx_t *ctx; ngx_http_gzip_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); if (!conf->enable || (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_FORBIDDEN && 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中对content_type做了校验 || ngx_http_test_content_type(r, &conf->types) == NULL || r->header_only) { return ngx_http_next_header_filter(r); } … }

ngx_http_test_content_type定义如下:

void * ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash) { u_char c, *lowcase; size_t len; ngx_uint_t i, hash; if (types_hash->size == 0) { return (void *) 4; } if (r->headers_out.content_type.len == 0) { return NULL; } len = r->headers_out.content_type_len; if (r->headers_out.content_type_lowcase == NULL) { lowcase = ngx_pnalloc(r->pool, len); if (lowcase == NULL) { return NULL; } r->headers_out.content_type_lowcase = lowcase; hash = 0; for (i = 0; i < len; i++) { c = ngx_tolower(r->headers_out.content_type.data[i]); hash = ngx_hash(hash, c); lowcase[i] = c; } r->headers_out.content_type_hash = hash; } return ngx_hash_find(types_hash, r->headers_out.content_type_hash, r->headers_out.content_type_lowcase, len); }

可以看出,将content-type头域内容转换为了小写,并使用了r->headers_out.content_type_len长度的内容,与配置的types进行比较。

但是针对第1种情况,配置和实际响应头明明是不相等的啊,是这么匹配成功的?

使用gdb打断点,发现

r->headers_out.content_type为:{len = 24, data = “image/jpeg;charset=UTF-8”}但是,r->headers_out.content_type_len却是10!这个与上面为什么不一致呢?

找到设置content_type的地方:

static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { ngx_uint_t i; // 此时,r->headers_out.content_type_len与 value->len 还是相等的 r->headers_out.content_type_len = value->len; #if 1 for (i = 0; i < value->len; i++) { if (value->data[i] == 😉 { // 找到第一个分号,然后修改了r->headers_out.content_type_len r->headers_out.content_type_len = i; break; } } #endif r->headers_out.content_type = *value; r->headers_out.content_type_hash = hv->hash; r->headers_out.content_type_lowcase = NULL; value->len = 0; return ngx_http_set_header_helper(r, hv, value, NULL, 1); }

可以看出,nginx只使用了Content-Type响应头中第一个分号前的内容进行匹配。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。


© 版权声明
THE END
★喜欢这篇文章吗?喜欢的话,麻烦动动手指支持一下!★
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容