我对该/info
位置有一个简单的nginx配置。
location /info {
uwsgi_read_timeout 20s;
uwsgi_send_timeout 20s;
uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;
}
该位置需要缓存。所以我加了
proxy_cache info_cache;
proxy_cache_valid 200 10m;
到此配置。工作正常。
过了一会儿,我们意识到应用程序的一些老错误客户端正在发送headerIf-None-Match
和304 Not Modified
预期的nginx交付。问题是这些客户正在等待200 OK
一个响应主体。不幸的是,我们无法全部修复它们。
Nginx是否有可能忽略If-None-Match
并仍从缓存中传递数据?
经过几次测试后,即使删除标头值proxy_set_header If-None-Match "";
,如果内容来自缓存,nginx也会检查If-None-Match
。请记住,这是通过代理传递的,不是静态的。
你是否尝试过将http://nginx.org/r/if_modified_since从默认值更改exact
为off
?
if_modified_since off;
根据我对src/http/modules/ngx_http_not_modified_filter_module.c
::的ngx_http_not_modified_header_filter()
阅读:
如果标头If-Modified-Since
存在(并且是非空的),并且if_modified_since
伪指令设置为off
(在源代码中),则立即返回true,从而导致过滤器与;短路。换句话说,在这种情况下,逻辑将不会执行。NGX_HTTP_IMS_OFF
define
ngx_http_test_if_modified()
return ngx_http_next_header_filter(r)
If-None-Match
请注意,只有If-Modified-Since
在请求中实际存在标头(并且不为空)(除了If-None-Match
你要处理的标头)时,这种情况才会发生,否则,代码路径将继续,而该NGX_HTTP_IMS_OFF
设置无效。我认为这里的期望是,如果客户已经包含If-None-Match
,那么If-Modified-Since
也可能会包含;因此,似乎没有一个单独的选项可以禁用对If-None-Match
特定对象和个别对象的处理。
78 if (r->headers_in.if_modified_since || r->headers_in.if_none_match) {
79
80 if (r->headers_in.if_modified_since
81 && ngx_http_test_if_modified(r))
82 {
83 return ngx_http_next_header_filter(r);
84 }
85
86 if (r->headers_in.if_none_match
87 && !ngx_http_test_if_match(r, r->headers_in.if_none_match))
88 {
89 return ngx_http_next_header_filter(r);
90 }
…
132ngx_http_test_if_modified(ngx_http_request_t *r)
133{
…
139 if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
140 return 1;
141 }
请注意,仅在或更高版本中提供ETag
支持,以及,而If-None-Match
在stable-1.4
或更高版本中不提供支持stable-1.2
,因此降级也可能是一种选择。
你是否尝试过清除ETag
客户之前的费用?
你的客户发送If-None-Match: *
吗?如果是这样,那么根据https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26,不执行GET操作将是正确的(例如,返回304 Not Modified
完全正确),这就是正确的nginx的功能,可以通过curl -H"If-None-Match: *" -v localhost:80
在nginx / 1.15.9的默认安装上运行类似的内容来轻松验证(请注意,stable-1.2
它没有ETag
或不If-None-Match
支持,因为它们最初与一起出现stable-1.4
)。
如果不是,你可以尝试ETag
在响应中省略,以欺骗客户端不发送If-None-Match
。
你可以使用http://nginx.org/r/add_header清除ETag
响应客户端的标头:
add_header ETag "";
顺便说一句,我也尝试过$http_if_none_match
直接使用http://nginx.org/r/set进行修改,但是没有任何效果。
作为最后的选择,如果没有更好的解决方案(尽管我认为上述解决方案也可能会奏效),你可以做的是将Nginx的另一个实例放在常规缓存Nginx的前面,专门用于那些有漏洞的客户端。在这个新的nginx实例中,你将禁用各种缓存,删除有问题的客户端应用程序未正确处理的标头,然后将请求传递给进行缓存的nginx普通实例。
更具体地说,你可能要确保该新实例也不会进行任何缓冲,例如http://nginx.org/r/proxy_buffering,否则,你可能会因将内容保存到以下步骤而冒着降低性能的风险。额外的实例再次将磁盘重新放置;否则,应该全部复制到内存中,并且速度可能足够快。
我认为这种方法绝对应该有效,因为该前端nginx不会有任何缓存,因此,如果使用http:/清除前端nginx上的304 Not Modified
,则后端nginx将不会收到,而后端nginx将不会收到。/nginx.org/r/proxy_set_header,然后对后端nginx进行http://nginx.org/r/proxy_pass。If-None-Match
If-None-Match
PS另一个答案建议使用http://nginx.org/r/proxy_ignore_headers,但是,根据围绕它的文档以及http://nginx.org/r/proxy_set_header周围的文档,似乎不If-None-Match
应该洒水任何差异;另外,看起来无论如何都没有_set_header
变种uwsgi
。
PPS如果你实际上不需要从缓存中交付内容,则另一个可能的途径是将http://nginx.org/r/uwsgi_cache_revalidate从默认值更改off
为on
;但是,我认为这也将取决于版本中_set_header
缺少的uwsgi
。