Ответы HTTP_IF_MODIFIED_SINCE и HTTP_IF_NONE_MATCH в PHP - PullRequest
11 голосов
/ 04 января 2010

У меня кешируемый динамический контент, созданный в PHP 5.1.0+. Я уже отправляю правильные заголовки (включая Last-Modified и ETag) клиентам.

Теперь я хочу, чтобы мой сценарий мог отвечать $_SERVER['HTTP_IF_MODIFIED_SINCE'] и $_SERVER['HTTP_IF_NONE_MATCH'] при его наличии. Когда условия совпадают, я хочу ответить HTTP 304 "Not Modified" клиентам.

Каковы правильные условия? Когда именно я выпускаю 304 вместо всего контента?

Принятый ответ на вопрос Как узнать, когда отправлять ответ 304 Not Modified * Кажется, это правильно выдает 1011 *, но у меня трудные времена для переноса этого кода в PHP 5.

Спасибо!

Ответы [ 7 ]

31 голосов
/ 06 января 2010

Я всегда использовал:

function caching_headers ($file, $timestamp) {
    $gmt_mtime = gmdate('r', $timestamp);
    header('ETag: "'.md5($timestamp.$file).'"');
    header('Last-Modified: '.$gmt_mtime);
    header('Cache-Control: public');

    if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
        if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
            header('HTTP/1.1 304 Not Modified');
            exit();
        }
    }
}

Не помню, написал я это или получил откуда-то еще ...

Я обычно использую его в начале файла следующим образом:

caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME']));
3 голосов
/ 04 января 2010

Ответ, на который вы ссылаетесь, кажется, содержит все, что вам нужно. Подведем итог:

  • создайте свои собственные заголовки ETag и Last-Modified, как если бы вы отправляли все тело
  • посмотрите заголовок If-Modified-Since, который отправил клиент, если ваш последний последний измененный старше или тот же самый, отправьте 304
  • посмотрите заголовок If-None-Match клиента, если он совпадает с вашим собственным ETag, отправьте 304
  • если вы достигнете этого места, заголовки не совпадают, отправьте полное тело и новые заголовки ETag / Last-Modified
1 голос
/ 24 августа 2018

Если бы я мог немного улучшить первоначальный блестящий ответ Рича Брэдшоу https://stackoverflow.com/users/16511/rich-bradshaw

Этот код изменен, и теперь 100% проходит проверки If-Modified-Since и If-None-Match. Он также правильно форматирует дату последнего изменения, так как оригинальный ответ отправляет +0000 в конце вместо GMT и добавляет заголовок VARY к ответу 304. Вы можете проверить это на redbot.org

<?php
function caching_headers ($file, $timestamp) {
    $lastModified=filemtime($_SERVER['SCRIPT_FILENAME']);
    $gmt_mtime = gmdate("D, d M Y H:i:s T", $lastModified);
    header('ETag: "'.md5($timestamp.$file).'"');
    header('Last-Modified: '.$gmt_mtime);
    header('Cache-Control: must-revalidate, proxy-revalidate, max-age=3600');

    if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
        if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
            header('HTTP/1.1 304 Not Modified');
            header("Vary: Accept-Encoding,User-Agent");
            exit();
        }
    }
}
caching_headers ($_SERVER['SCRIPT_FILENAME'], filemtime($_SERVER['SCRIPT_FILENAME']));
?>
1 голос
/ 04 января 2010

Вот фрагмент моей функции render_file ().

$last_modified = filemtime($filename);
if ($last_modified === false) {
  throw new Exception('Modify date unknown');
}
if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
  $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']));
  if ($if_modified_since >= $last_modified) { // Is the Cached version the most recent?
    header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified');
    exit();
  }
}
header('Last-Modified: '.date('r', $last_modified)); // tz should be GMT according to specs but also works with other tzs

// other headers and contents go here  
0 голосов
/ 18 декабря 2011

Эта статья ответит на все ваши вопросы по кешированию

Я обнаружил, что добавление

RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]

В нижней части моего файла htaccess (ниже всех rewriterule) работал.

0 голосов
/ 06 января 2010

Почему?

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

C.

0 голосов
/ 04 января 2010

Если клиент выполнил условный запрос GET и доступ разрешено, но документ не был модифицированный, сервер ДОЛЖЕН ответить с этим кодом состояния. 304 ответ НЕ ДОЛЖЕН содержать тело сообщения, и, следовательно, всегда завершается первой пустой строкой после полей заголовка.

С - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5

Итак, если вы отправляете 304, не отправляйте тело.

...