如何通过Nginx在gzip压缩上解决弱的etags转换

时间:2019-03-22 18:20:17

标签: nginx lua openresty

我正在尝试使用nginx中的gzip压缩某些端点的响应主体。问题在于nginx将上游应用程序生成的etag标记为弱(前缀为“ W /”)。上游应用还没有较弱的etag支持(春季版本<4.3)。当客户发回弱etag时,它与应用程序计算的强etag不匹配,我看不到304状态,但看到200的正文。即使应用程序的etag较弱,它也比修改所有应用程序,升级它们和现在启用弱标签更容易在一层中管理压缩。

我正在尝试两种选择:

  1. 当上游服务器发送一个强大的etag并且nginx gzip将其修改为一个弱etag时,请尝试使用nginx lua API将其修改回为强。

  2. 当客户端发回弱etag时,请剥离弱etag标识符(“ W /”)并将请求转发给应用。

我在nginx配置和lua API的使用中一定做错了我无法实现的目标。此问题与选项1有关。

Nginx配置:

  location /test/compression {
  proxy_pass              http://upstream_server:8080/someapi;
  proxy_redirect          default;
  proxy_set_header        X-Real-IP               $remote_addr;
  proxy_set_header        X-Forwarded-For         $proxy_add_x_forwarded_for;

  include compression.conf;

  header_filter_by_lua_block {
          ngx.header["ETag"] = string.substring(ngx.header["ETag"], 2);
      }
  }

compression.conf

gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_types application/json application/octet-stream;
gzip_min_length 10000;
gzip_comp_level 7;

实际结果:nginx日志错误:

nginx  | 2019/03/21 14:11:06 [error] 38#38: *8 failed to run header_filter_by_lua*: header_filter_by_lua:2: attempt to call field 'substring' (a nil value)
nginx  | stack traceback:
nginx  |    header_filter_by_lua:2: in function <header_filter_by_lua:1> while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /test/compression HTTP/1.1", upstream: "http://upstream_server:8080/someapi", host: "localhost:9696"

预期结果:对客户的响应中具有强大的ETag

经过此操作之后,还尝试了另一种方法来检索ETag标头:nginx - read custom header from upstream server

  location /test/compression {
  proxy_pass              http://upstream_server:8080/someapi;
  proxy_redirect          default;
  proxy_set_header        X-Real-IP               $remote_addr;
  proxy_set_header        X-Forwarded-For         $proxy_add_x_forwarded_for;

  include compression.conf;
  set $etag $upstream_http_etag

  header_filter_by_lua_block {
          ngx.header["ETag"] = string.substring(ngx.var.etag, 2);
      }
  }

相同的错误。

2 个答案:

答案 0 :(得分:1)

最后,我最终改为从客户端修改“ If-None-Match”请求标头。

  1. 如果客户端在“ If-None-Match”请求标头中发送了弱etag,请在nginx重写阶段使用lua或set nginx指令将其修改为强etag。
  2. 如果客户端在“ If-None-Match”请求标头中发送了强烈的etag,请保持原样。
  3. 如果从上游收到304响应,则不会调用nginx gzip模块,并且强大的etag返回给客户端。我已经离开了header_filter_by_lua_block块,因此对304个响应进行了从强到弱的etag转换。

此解决方案对我有用。 欢迎提出以更好的方式进行操作的建议。

答案 1 :(得分:0)

每当Nginx修改响应主体(请参见this code search)时,Nginx都会“削弱” ETag响应标头,包括对其进行压缩。

要首先避免这种情况的发生,可以disable the gzip modulegzip off)进行操作,或者,如果您具有相应的知识,可以尝试排除特定的内容类型。

另一个选择是更棘手的-尝试将Content-Encoding: identity添加到响应标头中(仅当首先没有内容编码标头时)。 我没有尝试过,但是阅读源代码应该可以:

ngx_http_gzip_filter_module.c L220

    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)
{
    return ngx_http_next_header_filter(r);
}