ngx_http_gzip_header_filter
1 定义
ngx_http_gzip_header_filter 函数 定义在 src/http/modules/ngx_http_gzip_filter_module.cstaticngx_int_tngx_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(r,&conf->types)==NULL||r->header_only){returnngx_http_next_header_filter(r);}r->gzip_vary=1;#if(NGX_HTTP_DEGRADATION){ngx_http_core_loc_conf_t*clcf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);if(clcf->gzip_disable_degradation&&ngx_http_degraded(r)){returnngx_http_next_header_filter(r);}}#endifif(!r->gzip_tested){if(ngx_http_gzip_ok(r)!=NGX_OK){returnngx_http_next_header_filter(r);}}elseif(!r->gzip_ok){returnngx_http_next_header_filter(r);}ctx=ngx_pcalloc(r->pool,sizeof(ngx_http_gzip_ctx_t));if(ctx==NULL){returnNGX_ERROR;}ngx_http_set_ctx(r,ctx,ngx_http_gzip_filter_module);ctx->request=r;ctx->buffering=(conf->postpone_gzipping!=0);ngx_http_gzip_filter_memory(r,ctx);h=ngx_list_push(&r->headers_out.headers);if(h==NULL){returnNGX_ERROR;}h->hash=1;h->next=NULL;ngx_str_set(&h->key,"Content-Encoding");ngx_str_set(&h->value,"gzip");r->headers_out.content_encoding=h;r->main_filter_need_in_memory=1;ngx_http_clear_content_length(r);ngx_http_clear_accept_ranges(r);ngx_http_weak_etag(r);returnngx_http_next_header_filter(r);}2 目的
ngx_http_gzip_header_filter是 Nginx Gzip 压缩模块的头部过滤器。
它的设计目的和必要性紧密围绕 HTTP 内容压缩这一核心功能。
这个函数的核心任务是:
在响应头发送之前,决定是否对当前响应启用 Gzip 压缩。
如果启用,则做好所有的初始化和响应头修改工作,
为后续的响应体压缩(由ngx_http_gzip_body_filter完成)
准备好运行环境。
3 详解
1 函数签名
staticngx_int_tngx_http_gzip_header_filter(ngx_http_request_t*r)1 返回值类型ngx_int_t:
返回一个整数状态码,表示执行结果(NGX_OK 成功,NGX_ERROR 出错)。
2ngx_http_gzip_header_filter:
函数名,表示 HTTP Gzip 模块的头部过滤器。
3ngx_http_request_t *r:
参数r是指向当前 HTTP 请求结构体的指针,包含请求的所有信息。
2 逻辑流程
1 条件过滤 筛选掉不需要 gzip 压缩的请求 2 处理需要 gzip 压缩的请求{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);获取 location 配置
1 条件过滤
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(r,&conf->types)==NULL||r->header_only){returnngx_http_next_header_filter(r);}快速退出条件检查
只要任何一个条件为真,就不进行Gzip压缩,
直接调用下一个头部过滤器并返回。各条件详解:
!conf->enable:配置中gzip未开启(值为 off 或 0)。
(r->headers_out.status != NGX_HTTP_OK && ...):
响应状态码不是 200、403、404 之一。Gzip只对少数成功或部分错误状态的响应体进行压缩,
避免浪费资源于无意义的响应(如 301 重定向没有响应体)。
(r->headers_out.content_encoding && r->headers_out.content_encoding->value.len):
响应头中已经存在Content-Encoding(例如上游已经压缩过),
不能再压缩,否则会损坏数据。
(r->headers_out.content_length_n != -1 && r->headers_out.content_length_n < conf->min_length):
如果 Content-Length 已知(不是 -1)且其值小于 min_length 配置(默认 20 字节),
压缩没有意义,还可能增大体积,跳过。
ngx_http_test_content_type(r, &conf->types) == NULL:响应的 Content-Type 不在 gzip_types 指定的类型列表中(默认只有 text/html)。
r->header_only:
这是一个 HEAD 请求,只要求返回响应头,没有响应体,无需压缩。
这些检查在头部过滤器执行,此时响应状态码、内容长度、内容类型等均已确定,
因此能够准确判断。任何条件不满足,都会导致函数直接放行,开销极低。
2 处理需要 gzip 压缩的请求
r->gzip_vary=1;#if(NGX_HTTP_DEGRADATION){ngx_http_core_loc_conf_t*clcf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);if(clcf->gzip_disable_degradation&&ngx_http_degraded(r)){returnngx_http_next_header_filter(r);}}#endifif(!r->gzip_tested){if(ngx_http_gzip_ok(r)!=NGX_OK){returnngx_http_next_header_filter(r);}}elseif(!r->gzip_ok){returnngx_http_next_header_filter(r);}ctx=ngx_pcalloc(r->pool,sizeof(ngx_http_gzip_ctx_t));if(ctx==NULL){returnNGX_ERROR;}ngx_http_set_ctx(r,ctx,ngx_http_gzip_filter_module);ctx->request=r;ctx->buffering=(conf->postpone_gzipping!=0);ngx_http_gzip_filter_memory(r,ctx);h=ngx_list_push(&r->headers_out.headers);if(h==NULL){returnNGX_ERROR;}h->hash=1;h->next=NULL;ngx_str_set(&h->key,"Content-Encoding");ngx_str_set(&h->value,"gzip");r->headers_out.content_encoding=h;r->main_filter_need_in_memory=1;ngx_http_clear_content_length(r);ngx_http_clear_accept_ranges(r);ngx_http_weak_etag(r);returnngx_http_next_header_filter(r);}