nginx proxy_cache 和 If-None-Match

nginx proxy_cache 和 If-None-Match

我有针对该位置的简单 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

  1. 你提到做http://nginx.org/r/uwsgi_pass,然后使用http://nginx.org/r/proxy_cache等,不与http://nginx.org/r/uwsgi_cache等。你确定它真的正常工作吗?我不知道这些指令是可以互换的——我认为它们根本就不能互换,尽管它们听起来确实很相似,做起来也类似。

  1. 你试过改变吗http://nginx.org/r/if_modified_since从默认的exactoff

    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),因此降级也可能是一种选择。


  1. 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没有ETagIf-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,但却没有任何效果。


  1. 作为最后的手段,如果没有更好的解决方案(尽管我认为上述解决方案也可以),您可以做的是将另一个 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从默认的offon;但是,我认为这也取决于_set_header,而版本中缺少这个uwsgi

相关内容