Назад | Перейти на главную страницу

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. Вы упоминаете, что делаете 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 по умолчанию 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() немедленно возвращает истину, что приводит к короткому замыканию фильтра с 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 не имеет 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 не было бы кеша, поэтому он не мог ответить с 304 Not Modified, тогда как серверный nginx не получит If-None-Match если вы очистите If-None-Match на веб-интерфейсе nginx с http://nginx.org/r/proxy_set_header прежде чем делать http://nginx.org/r/proxy_pass на бэкэнд nginx.


P.S. Другой ответ предлагает использовать http://nginx.org/r/proxy_ignore_headers, но, основываясь на документации вокруг него, а также вокруг http://nginx.org/r/proxy_set_header, это не похоже на окропление If-None-Match должно иметь значение; плюс, похоже, нет _set_header вариант для uwsgi в любом случае.

P.P.S. Другой потенциальный путь, если вам на самом деле не нужно доставлять вещи из кеша, - это изменение http://nginx.org/r/uwsgi_cache_revalidate по умолчанию off к on; однако я думаю, что это тоже будет зависеть от _set_header, который отсутствует в uwsgi версия.