Почему браузер не отправляет заголовок "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 в этом внимание, который в свою очередь приводит два ценных обсуждения по этому вопросу:
- нить форума NGINX обсуждает поведение.
-
касательное обсуждение в репозитории проекта; см. комментарий
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"
.
надеюсь, это может быть полезно для кого-то.