![nginx proxy_cache 和 If-None-Match](https://linux22.com/image/732436/nginx%20proxy_cache%20%E5%92%8C%20If-None-Match.png)
我有针对该位置的简单 nginx 配置/info
。
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;
按照此配置。它工作正常。
过了一段时间,我们意识到一些有缺陷的旧客户端我们的应用程序正在发送标头If-None-Match
,并且 nginx 交付304 Not Modified
符合预期。问题是这些客户端正在等待200 OK
加上响应主体。不幸的是,我们无法修复所有这些问题。
nginx 是否可能忽略缓存If-None-Match
并且仍然从缓存中传送?
经过几次测试后,即使删除了标头值,proxy_set_header If-None-Match "";
如果内容来自缓存,nginx 也会检查If-None-Match
。记住它来自代理传递,而不是静态的。
答案1
- 你提到做http://nginx.org/r/uwsgi_pass,然后使用http://nginx.org/r/proxy_cache等,不与http://nginx.org/r/uwsgi_cache等。你确定它真的正常工作吗?我不知道这些指令是可以互换的——我认为它们根本就不能互换,尽管它们听起来确实很相似,做起来也类似。
你试过改变吗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
(存在NGX_HTTP_IMS_OFF
define
在源代码中),然后ngx_http_test_if_modified()
立即返回 true,导致过滤器与 短路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 没有任何缓存,因此它不可能回复
304 Not Modified
,而If-None-Match
如果你If-None-Match
在前端 nginx 上清除http://nginx.org/r/proxy_set_header在做之前http://nginx.org/r/proxy_pass到后端nginx。
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
。