我正在尝试使用nginx中的gzip压缩某些端点的响应主体。问题在于nginx将上游应用程序生成的etag标记为弱(前缀为“ W /”)。上游应用还没有较弱的etag支持(春季版本<4.3)。当客户发回弱etag时,它与应用程序计算的强etag不匹配,我看不到304状态,但看到200的正文。即使应用程序的etag较弱,它也比修改所有应用程序,升级它们和现在启用弱标签更容易在一层中管理压缩。
我正在尝试两种选择:
当上游服务器发送一个强大的etag并且nginx gzip将其修改为一个弱etag时,请尝试使用nginx lua API将其修改回为强。
当客户端发回弱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);
}
}
相同的错误。
答案 0 :(得分:1)
最后,我最终改为从客户端修改“ If-None-Match”请求标头。
header_filter_by_lua_block
块,因此对304个响应进行了从强到弱的etag转换。 此解决方案对我有用。 欢迎提出以更好的方式进行操作的建议。
答案 1 :(得分:0)
每当Nginx修改响应主体(请参见this code search)时,Nginx都会“削弱” ETag响应标头,包括对其进行压缩。
要首先避免这种情况的发生,可以disable the gzip module(gzip 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);
}