Почему браузер не отправляет заголовок "If-None-Match"?

Я пытаюсь загрузить (и, надеюсь, кэшировать) динамически загруженное изображение в PHP. Вот заголовки, отправленные и полученные:

запрос:

GET /url:resource/Pomegranate/resources/images/logo.png HTTP/1.1
Host: pome.local
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: PHPSESSID=fb8ghv9ti6v5s3ekkmvtacr9u5

ответ:

HTTP/1.1 200 OK
Date: Tue, 09 Apr 2013 11:00:36 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.14 ZendServer/5.0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Disposition: inline; filename="logo"
ETag: "1355829295"
Last-Modified: Tue, 18 Dec 2012 14:44:55 Asia/Tehran
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: image/png

когда я перезагружаю URL, отправляются и принимаются те же самые заголовки. Мой вопрос в том, что я должен отправить в своем ответе, чтобы увидеть If-None-Match заголовок в последующем запросе?

примечание: Я считаю, что эти заголовки были в порядке не так давно, хотя я не могу будьте уверены, но я думаю, что браузеры изменены, чтобы не отправлять If-None-Match заголовок больше (я раньше видел этот заголовок). Я тестирую Chrome и Firefox, и оба не могут отправить заголовок.

3 ответов


скажете вы Cache-Control: no-store, no-cache - но ожидать кэширования произойдет?

удалите эти значения (я думаю must-revalidate, post-check=0, pre-check=0 может / должно быть сохранено – они говорят браузеру проверить с сервером, если было изменение).

и я бы придерживался Last-Modified самостоятельно (если изменения в ваших ресурсах могут быть обнаружены только с помощью этого критерия) -ETag более сложная вещь для обработки (особенно, если вы хотите иметь дело с ней в своем PHP-скрипте самостоятельно), и Google PageSpeed/YSlow советуют против этого тоже.


Та Же Проблема, Аналогичное Решение

я пытался определить, почему Google Chrome не будет отправлять If-None-Match заголовки при посещении сайта, который я разрабатываю. (Chrome 46.0.2490.71 m, хотя я не уверен, насколько актуальна версия.)

это другой - хотя и очень похожий - ответ, чем ОП, в конечном счете цитируемый (в комментарии относительно принятого ответа), но он затрагивает ту же проблему:

браузер не отправляет в последующих запросах "когда следует" (т. е. логика на стороне сервера, через PHP или аналогичный, использовалась для отправки ETag или Last-Modified заголовок в первом ответе).

предпосылки

использование самозаверяющего сертификата TLS, который делает блокировку Красной в Chrome, изменяет поведение кэширования Chrome. Прежде чем пытаться устранить проблему такого рода, установите самозаверяющий сертификат в эффективное доверенное корневое хранилище и полностью перезапустите браузер, как объяснено в https://stackoverflow.com/a/19102293 .

1-е прозрение: если-нет-Матч требует ETag с сервера, сначала

я довольно быстро понял, что Chrome (и, вероятно, большинство или все другие браузеры) не будет отправлять до сервер уже направил теги в ответ на предыдущий запрос. Логически, это имеет смысл; в конце концов, как это могло Хром отправить If-None-Match когда ему никогда не давали значения?

это заставляет меня взглянуть на мою логику на стороне сервера-в частности, как заголовки отправляются, когда я хочу, чтобы пользовательский агент кэшировал ответ-в попытке определить, по какой причине ETag заголовок не отправляется в ответ на самый первый запрос Chrome для ресурса. Я сделал расчетливое усилие, чтобы включить в моей логике приложения.

я использую PHP, поэтому @Mehran (ОП) комментарий выскочил на меня (он / она говорит, что звонит header_remove() перед отправкой желаемых заголовков, связанных с кэшем, решает проблему).

откровенно говоря, я скептически относился к этому решению, потому что а) я был уверен, что PHP не будет отправлять собственные заголовки по умолчанию (и это не так, учитывая мою конфигурацию); и Б) когда я позвонил var_dump(headers_list()); непосредственно перед установкой моих пользовательских заголовков кэширования в PHP, единственным набором заголовков был тот, который я устанавливал намеренно просто сверху:

header('Content-type: application/javascript; charset=utf-8');

Итак, мне нечего терять, я попытался позвонить header_remove(); непосредственно перед отправкой моих пользовательских заголовков. И к моему большому удивлению, PHP начал отправлять ETag заголовок внезапно!

2-е прозрение: gzipping ответ изменяет свой хэш

это тогда меня ударило меня, как мешок кирпичей: указав Content-type заголовок в PHP, я говорил NGINX (веб-сервер, который я использую), чтобы GZIP ответ, как только PHP вернет его NGINX! Быть ясным, the Content-type то, что я указывал, было в списке типов NGINX для gzip.

для тщательности Мои настройки NGINX GZIP следующие, А PHP подключен к NGINX через php-fpm:

gzip            on;
gzip_min_length 1;
gzip_proxied    expired no-cache no-store private auth;
gzip_types      text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;

gzip_vary on;

я задумался, почему NGINX может удалить ETag что я отправил в PHP, когда указан" gzippable " content-type, и придумал теперь очевидный ответ: потому что NGINX изменяет тело ответа, которое PHP передает обратно, когда NGINX gzips его! Это имеет смысл; нет точка в отправке ETag когда он не будет соответствовать ответу, используемому для его создания. Это довольно гладко, что NGINX обрабатывает этот сценарий так разумно.

я не знаю, всегда ли NGINX был достаточно умен, чтобы не сжимать тела ответов, которые в несжатом виде, но содержат ETag заголовки, но, похоже, именно это здесь и происходит.

обновление: я нашел комментарий, который объясняет поведение NGINX в этом внимание, который в свою очередь приводит два ценных обсуждения по этому вопросу:

  1. нить форума NGINX обсуждает поведение.
  2. касательное обсуждение в репозитории проекта; см. комментарий Posted on Jun 15, 2013 by Massive Bird.

в интересах сохранения этого ценного объяснения, если оно вдруг исчезнет, я цитирую из Massive Birdвклад в обсуждение:

Nginx полосы Etag при gzipping ответ на лету. Это согласно спецификации, поскольку ответ без gzipped не байт за байтом сравним сжатый ответ.

тем не менее, поведение NGINX в этом отношении может считаться немного ошибочным в том, что та же спецификация

... также говорит, что есть вещь, называемая слабым Etags (значение Etag префикс с W/), и говорит нам, что его можно использовать для проверки ответа семантически аналог. В этом случае Nginx не должен связываться с он. К сожалению, эта проверка никогда не попадала в исходное дерево [цитата теперь заполнена спамом, к сожалению]."

я не уверен в текущем расположении NGINX в этом отношении, и, в частности, добавил ли он поддержку "слабых" Etags.

Итак, какое решение?

Итак, каково решение для получения ETag вернуться в ответ? Сделайте gzipping в PHP, чтобы NGINX видит, что ответ уже сжат, и просто передает его, оставляя ETag заголовок нетронутыми:

ob_start('ob_gzhandler');

как только я добавил этот вызов до отправки заголовков и тела ответа, PHP начал отправлять ETag значение с каждым ответом. Да!

Другие Уроки

вот некоторые интересные лакомые кусочки, полученные из моих исследований. Эта информация довольно удобна при попытке протестировать реализацию кэширования на стороне сервера, будь то на PHP или другом языке.

Chrome и его панель инструментов разработчика "Net" ведут себя по-разному в зависимости от того, как запрос инициируется.

если запрос "сделан свежим", например, нажав Ctrl+F5, Chrome отправляет следующие заголовки:

Cache-Control: no-cache
Pragma: no-cache

и сервер отвечает 200 OK.

если запрос сделан только с F5, Chrome отправляет следующие заголовки:

Pragma: no-cache

и сервер отвечает 304 Not Modified.

наконец, если запрос сделан, нажав на ссылку на страницу, которую вы уже просматриваете,или поместив фокус в адресную строку Chrome и нажав Enter, Chrome отправляет следующие заголовки:

Cache-Control: no-cache
Pragma: no-cache

и сервер отвечает 200 OK (from cache).

хотя это поведение немного сбивает с толку сначала, если вы не знаете, как это работает, это идеальное поведение, потому что оно позволяет проверить каждый возможный сценарий запроса / ответа очень тщательно.

возможно, наиболее запутанным является то, что Chrome автоматически вставляет Cache-Control: no-cache и Pragma: no-cache заголовки в исходящем запросе когда на самом деле Chrome получает ответы из своего кэша (о чем свидетельствует 200 OK (from cache) ответ).

этот опыт был довольно информативным для меня, и я надеюсь, что другие найдут этот анализ ценности в будущем.


похожие проблемы

я пытался получить условный запрос GET с If-None-Match заголовок, поставив правильный Etag заголовок, но безрезультатно в любом браузере я пробовал.

после многих испытаний я понимаю, что браузеры относятся к обоим GET и POST к тому же пути, что и тот же кандидат кэша. Таким образом,GET при правильной Etag был эффективно отменен с немедленным "POST" на тот же путь с Cache-Control:"no-cache, private", хотя он был поставлен X-Requested-With:"XMLHttpRequest".

надеюсь, это может быть полезно для кого-то.