Gena Makhomed
November 29, 2018 01:36PM
On 29.11.2018 18:30, Maxim Dounin wrote:

>> В документации к директиве fastcgi_cache_key приведен такой пример:
>>
>> fastcgi_cache_key localhost:9000$request_uri;
>>
>> У этого примера есть несколько проблем:
>>
>> 1. Если кто-то сделает к бекенду HEAD-запрос, то в кеш запишется пустой
>> ответ и на последующие GET-запросы будет отдаваться пустая страница.

> AFAIK, никакой специальной обработки HEAD-запросов в FastCGI не
> предусмотрено. И в том числе не предсмотрено в каком-нибудь PHP
> из коробки. Соответственно всё будет работать штатно.

Специальная обработка HEAD-запросов предусмотрена в HTTP протоколе:
https://tools.ietf.org/html/rfc7231#section-4.3.2

The HEAD method is identical to GET except that the server MUST NOT
send a message body in the response (i.e., the response terminates at
the end of the header section).

В nginx присутствует workaround, который исправляет поведение бекендов,
которые на HEAD-запрос *ошибочно* отвечают так же, как и на GET-запрос.

Но далеко не все бекенды содержат в себе эту ошибку, многие из них ведут
себя именно так, как этого от них требует спецификация HTTP протокола.

> Речь про какие-то фреймворки, которые обрабатывают
> HEAD автоматически, не донося соответствующую информацию до кода?
> Или про какой-то стандартный софт, который не возвращает тело для
> HEAD-запросов?

Какая разница, сам софт или фрейморк используемый софтом в каждом
конкретном случае обрабатывает HEAD запросы согласно требований RFC?

Эта проблема встречается не только у меня, вот например:

https://www.claudiokuenzler.com/blog/705/empty-blank-page-nginx-fastcgi-cache-head-get

https://serverfault.com/a/612729

> Отдельно отмечу, что правильный вариант работы с HEAD-запросами
> для целей кэширования - это отправлять на бэкенд GET-запросы, и
> кэшировать ответ. Именно так делает proxy-модуль.

В proxy модуле есть директива proxy_cache_convert_head, которая
имеет значение on по-умолчанию, поэтому там все работает нормально.
В fastcgi/uwsgi/scgi модулях аналогичной директивы нет.

> В случае
> FastCGI подобная автоматическая конвертация не работает, так как
> метод запроса не отправляется на бэкенд иначе как через
> произвольно заданный fastcgi_param,

Нет.

FastCGI - это расширение протокола CGI, а протокол CGI *требует*,
чтобы параметр REQUEST_METHOD присутствовал в каждом запросе:

https://tools.ietf.org/html/rfc3875#section-4.1.12

The REQUEST_METHOD meta-variable MUST be set to the method which
should be used by the script to process the request, as described in
section 4.3.

REQUEST_METHOD = method
method = "GET" | "POST" | "HEAD" | extension-method
extension-method = "PUT" | "DELETE" | token

> да и сама конвертация
> представляется ненужной, так как в типичном случае ответы на
> HEAD-запросы не отличаются от таковых на GET-запросы.

Но ведь не все бекенды нарушают требование HTTP протокола,
есть и такие, которые обрабатывают HEAD-запросы правильно.

> Однако если
> вдруг она нужна - это можно сделать, просто передав в
> fastcgi_param GET вместо HEAD.

Можете привести фрагмент конфига, как это можно сделать?

>> 2. Как правило на современных серверах размещено больше одного сайта.
>> При такой настройке как рекомендуется в документации - кеш будет
>> представлять собой смесь из содержимого разных сайтов и нормально
>> работать не будет.

> Вопрос тут в том, что именно является идентификатором
> запрашиваемого ресурса. Пример в документации предполагает, что
> мы коннектимся на localhost:9000, и получаем там ответы,
> идентифицируемые URI запроса.

Идентификатором ресурса является https://en.wikipedia.org/wiki/URI
который включает в себя и scheme и host и path[?query] ($request_uri)

> Это в общем случае верно для конфигурации, которая приводится в
> описании модуля fastcgi, и с этой конфигурацией приведённый пример
> fastcgi_cache_key будет работать корректно. Если конфигурация
> другая - fastcgi_cache_key может потребоваться другой. Однако
> проблема в том, что без знания конфигурации - неизвестно, какой
> именно fastcgi_cache_key потребуется.

Поэтому я и предлагаю написать в документации пример
директивы, который будет корректно работать *всегда*.

>> 3. если бекенд возвращает для HTTP-версии сайта редирект на HTTPS версию
>> сайта, такое значение fastcgi_cache_key бужет приводить к проблемам,
>> так как для HTTPS-запроса будет возвращаться 301 редирект из кеша.
>>
>> Можно ли исправить документацию и написать там в качестве примера
>> такой фрагмент:
>>
>> fastcgi_cache_key "$request_method $scheme://$host$request_uri";
>>
>> такая директива работает нормально, нет трех вышеперечисленных проблем.

> Ключём кэширования должен выступать идентификатор ресурса,
> который запрашивается с бэкенда.

Идентификатор ресурса - это URI, в случае HTTP протокола.

> В предложенном варианте -
> отсутствует какая-либо информация о бэкенде вообще, так что он
> представляется мне идеалогически неверным.

А в чем тут практическая проблема, если в fastcgi_cache_key
отсутствует информация о бекенде? Или проблемы никакой нет?

> У нас, конечно, уже есть подобная конструкция в описании
> proxy_cach_key, но там за счёт $cookie_user куда более очевидно,
> что это именно пример, а не что-то, отлитое в граните и пригодное
> для всех конфигов. Возможно, по какому-то такому пути и стоит пойти.

В документации к директиве proxy_cache_convert_head написано:

When the conversion is disabled, the cache key
should be configured to include the $request_method.

А поскольку для fastcgi/uwsgi/scgi аналогичной директивы
fastcgi/uwsgi/scgi_cache_convert_head нет, то и требование

the cache key should be configured to include the $request_method

должно выполняться всегда.

>> Недавно в очередной раз столкнулся в проблемой, когда люди бездумно
>> копируют в конфиг рекомендуемые варианты директивы fastcgi_cache_key
>> из документации, не подозревая, что в документации записано в качестве
>> рекомендуемого варианта то, что нормально работать у них не будет.
>
> Кажется, что правильным будет для начала написать в описании
> fastcgi_cache_key (uwsgi_cache_key, scgi_cache_key), что ключ
> должен идентифицировать запрашиваемый ресурс, а не ставится "абы
> как, авось повезёт".

Максим, так я ведь именно об этом и говорю. Идентификатором ресурса
является URI в случае HTTP протокола, из этого следует, что
fastcgi_cache_key (uwsgi_cache_key, scgi_cache_key) *должны*
включать в себя и $scheme и $host а не только path[?query],
которые в nginx хранятся в переменной $request_uri.

https://tools.ietf.org/html/rfc7230#section-2.7

Uniform Resource Identifiers (URIs) [RFC3986] are used throughout
HTTP as the means for identifying resources (Section 2 of [RFC7231]).

--
Best regards,
Gena

_______________________________________________
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru
Subject Author Posted

Документация к директиве fastcgi_cache_key

Gena Makhomed November 29, 2018 10:00AM

Re: Документация к директиве fastcgi_cache_key

Maxim Dounin November 29, 2018 11:32AM

Re: Документация к директиве fastcgi_cache_key

Gena Makhomed November 29, 2018 01:36PM

Re: Документация к директиве fastcgi_cache_key

Maxim Dounin November 29, 2018 02:04PM

Re: Документация к директиве fastcgi_cache_key

Gena Makhomed November 30, 2018 04:32AM

Re: Документация к директиве fastcgi_cache_key

Илья Шипицин November 30, 2018 05:38AM

Re: Документация к директиве fastcgi_cache_key

Константин Ткаченко December 03, 2018 04:04AM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 305
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready