Warm tip: This article is reproduced from serverfault.com, please click

http-nginx proxy_cache和If-None-Match

(nginx proxy_cache and If-None-Match)

发布于 2021-03-19 08:36:39

我对该/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-Match304 Not Modified预期的nginx交付问题是这些客户正在等待200 OK一个响应主体。不幸的是,我们无法全部修复它们。

Nginx是否有可能忽略If-None-Match并仍从缓存中传递数据?

经过几次测试后,即使删除标头值proxy_set_header If-None-Match "";,如果内容来自缓存,nginx也会检查If-None-Match请记住,这是通过代理传递的,不是静态的。

Questioner
Jonathan Prates
Viewed
0
cnst 2019-01-25 13:18:30
  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在源代码中),则立即返回true,从而导致过滤器与;短路换句话说,在这种情况下,逻辑将不会执行。NGX_HTTP_IMS_OFF definengx_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-Matchstable-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它没有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进行修改,但是没有任何效果。


  1. 作为最后的选择,如果没有更好的解决方案(尽管我认为上述解决方案也可能会奏效),你可以做的是将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_passIf-None-MatchIf-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从默认值更改offon但是,我认为这也将取决于版本中_set_header缺少的uwsgi