Является ли моя реализация HTTP-условного получения ответов на PHP в порядке?


После долгих поисков, прочтения всех учебников, которые я нашел, и задав здесь несколько вопросов, мне наконец удалось правильно ответить (по крайней мере, я думаю) на запросы if-none-match и if-modified-с HTTP.

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

session_cache_limiter('public'); //Cache on clients and proxies
session_cache_expire(180); //3 hours
header('Content-Type: ' . $documentMimeType . '; charset=' . $charset);
header('ETag: "' . $eTag . '"'); //$eTag is a MD5 of $currentLanguage + $lastModified
if ($isXML)
    header('Vary: Accept'); //$documentMimeType can be either application/xhtml+xml or text/html for XHTML (based on $_SERVER['HTTP_ACCEPT'])
header('Last-Modified: ' . $lastModified);
header('Content-Language: ' . $currentLanguage);

Кроме того, каждая страница имеет свой собственный URL-адрес (для всех языков). Например, "index.php "будет подаваться по URL "/en/home" на английском языке и "/fr/accueil" на французском языке.

Мой большой проблема заключалась в том, чтобы ответить на "304 Не изменено", если-нет-совпадения и если-изменено-с HTTP-запросов только при необходимости.

Лучший документ, который я нашел, это: http://rithiur.anthd.com/tutorials/conditionalget.php

И это реализация, которую я сделал (этот фрагмент кода называется ASAP на страницах, которые можно кэшировать):

$ifNoneMatch = array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false;
$ifModifiedSince = array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;

if ($ifNoneMatch !== false && $ifModifiedSince !== false)
{
    //Both if-none-match and if-modified-since were received.
    //They must match the document values in order to send a HTTP 304 answer.
    if ($ifNoneMatch == $eTag && $ifModifiedSince == $lastModified)
    {
        header('Not Modified', true, 304);
        exit();
    }
}
else
{
    //Only one header received, it it match the document value, send a HTTP 304 answer.
    if (($ifNoneMatch !== false && $ifNoneMatch == $eTag) || ($ifModifiedSince !== false && $ifModifiedSince == $lastModified))
    {
        header('Not Modified', true, 304);
        exit();
    }
}

Мой вопрос состоит из двух частей:

  • Правильно ли это делать? Я имею в виду, когда если-нет-совпадения и если-изменено-с тех пор отправлено, оба должны совпадать, чтобы ответить на 304, и если отправлен только один из двух, только совпадающий с этим, можно отправить 304?
  • При использовании в контексте, описанном здесь, являются ли эти 2 фрагмента общедоступными для кэша (я имею в виду кэш, дружественный к прокси и веб-браузерам)?

Кстати, я использую только PHP 5.1.0+ (я не поддерживаю версии ниже этой).

Правка: Добавлена награда... Я ожидаю качественного ответа. Не отвечайте/не голосуйте, если вы о чем-то догадываетесь!

Author: AlexV, 2010-01-07

1 answers

  • Это не совсем правильно. Пожалуйста, взгляните на алгоритм: альтернативный текст http://img532.imageshack.us/img532/1017/cache.png
  • Решение подходит для прокси-серверов, вы можете использовать Cache-control: прокси-повторная проверка, чтобы заставить кэши подчиняться любой информации о свежести, которую вы им предоставляете о ресурсе (применяется только к общим|прокси-кэшам)

Вот функция, которая может помочь:

function isModified($mtime, $etag) {
    return !( (
        isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
        && 
        strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mtime
    ) || (
        isset($_SERVER['HTTP_IF_NONE_MATCH'])
        && 
        $_SERVER['HTTP_IF_NONE_MATCH'] == $etag
    ) ) ;
}

Я предлагаю вам взглянуть на следующую статью: http://www.peej.co.uk/articles/http-caching.html

Обновление:

[ ALEXV] Возможно ли вообще получить, если-нет-совпадения И если-изменено-с тех пор одновременно?

Вы определенно можете установить оба набора. Однако:

Если ни один из тегов сущности не совпадает, сервер МОЖЕТ выполнить запрошенный метод, как если бы поле заголовка If-None-Match не существовало, но также должно игнорировать любой заголовок If-Modified-Since поле(поля) в запросе. То есть, если теги сущностей не совпадают, сервер НЕ ДОЛЖЕН возвращать ответ 304 (не измененный).

RFC2616 #14.26

Пример значений (W означает "слабый"; подробнее читайте в RFC2616 #13.3.3):

If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
If-None-Match: *

В качестве особого случая значение "*" соответствует любой текущей сущности ресурса.

 22
Author: St.Woland, 2010-01-14 22:07:44