Как узнать, когда отправлять ответ 304 Без изменений

StackOverflow https://stackoverflow.com/questions/4506

  •  08-06-2019
  •  | 
  •  

Вопрос

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

  1. Какие окончательные HTTP-заголовки мне нужно проверить, чтобы точно знать, следует ли мне отправлять ответ 304, и что я ищу, когда я их проверяю?

  2. Кроме того, есть ли какие-либо заголовки, которые мне нужно отправить при первоначальной отправке файла (например, 'Last-Modified') в качестве ответа 200?

Какой-нибудь псевдокод, вероятно, был бы наиболее полезным ответом.


А как насчет заголовка cache-control?Могут ли различные возможные значения этого параметра повлиять на то, что вы отправляете клиенту (а именно max-age), или следует выполнять только if-modified-since?

Это было полезно?

Решение

Вот как я это реализовал.Код работает чуть больше года и с несколькими браузерами, так что я думаю, что он довольно надежный.Это основано на RFC 2616 и наблюдая за тем, что и когда отправляли различные браузеры.

Вот псевдокод:

server_etag = gen_etag_for_this_file(myfile)
etag_from_browser = get_header("Etag")

if etag_from_browser does not exist:
    etag_from_browser = get_header("If-None-Match")
if the browser has quoted the etag:
    strip the quotes (e.g. "foo" --> foo)

set server_etag into http header

if etag_from_browser matches server_etag
    send 304 return code to browser

Вот фрагмент моей серверной логики, которая обрабатывает это.

/* the client should set either Etag or If-None-Match */
/* some clients quote the parm, strip quotes if so    */
mketag(etag, &sb);

etagin = apr_table_get(r->headers_in, "Etag");
if (etagin == NULL)
    etagin = apr_table_get(r->headers_in, "If-None-Match");
if (etag != NULL && etag[0] == '"') {
    int sl; 
    sl = strlen(etag);
    memmove(etag, etag+1, sl+1);
    etag[sl-2] = 0;
    logit(2,"etag=:%s:",etag);
}   
... 
apr_table_add(r->headers_out, "ETag", etag);
... 
if (etagin != NULL && strcmp(etagin, etag) == 0) {
    /* if the etag matches, we return a 304 */
    rc = HTTP_NOT_MODIFIED;
}   

Если вам нужна помощь с генерацией etag, задайте другой вопрос, и я откопаю какой-нибудь код, который также это делает.ХТХ!

Другие советы

Ответ 304 Not Modified может быть результатом запроса GET или HEAD с заголовком If-Modified-Since ("IMS") или If-Not-Match ("INM").

Чтобы решить, что делать, когда вы получите эти заголовки, представьте, что вы обрабатываете запрос GET без этих условных заголовков.Определите, какие значения вашего ETag и заголовков с последним изменением будут в этом ответе, и используйте их для принятия решения.Надеюсь, вы построили свою систему таким образом, что определение этого менее затратно, чем построение полного ответа.

Если существует INM и значение этого заголовка совпадает со значением, которое вы бы поместили в ETag, то ответьте 304.

Если есть IMS и значение даты в этом заголовке более позднее, чем то, которое вы поместили бы в Последнее измененное, то ответьте 304.

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

Для подхода с наименьшими усилиями к части 2 вашего вопроса выясните, какие из заголовков (Expires, ETag и Last-Modified) вы можете легко и корректно создать в своем веб-приложении.

Для получения рекомендуемых материалов для чтения:

http://www.w3.org/Protocols/rfc2616/rfc2616.html

http://www.mnot.net/cache_docs/

Вам следует отправить сообщение 304, если клиент явно указал, что, возможно, эта страница уже есть в его кэше.Это называется условным получением, которое должно включать в себя если-изменено-с тех пор, как заголовок в запросе.

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

Видишь http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 для соответствующего раздела в RFC.

Мы также обрабатываем кэшированные, но защищенные ресурсы.Если вы отправляете / генерируете заголовок ETag (что рекомендуется в разделе 13.3 RFC 2616), то клиент ДОЛЖЕН использовать его в условном запросе (обычно в заголовке If-None-Match - HTTP_IF_NONE_MATCH).Если вы отправляете заголовок с последним изменением (опять ЖЕ, вы ДОЛЖНЫ ЭТО СДЕЛАТЬ), то вам следует проверить заголовок If-Modified-Since - HTTP_IF_MODIFIED_SINCE.Если вы отправляете и то, и другое, то клиент ДОЛЖЕН отправить и то, и другое, но он ДОЛЖЕН отправить ETag.Также обратите внимание, что validtion просто определяется как проверка условных заголовков на строгое равенство с теми, которые вы бы отправили.Кроме того, для ранжированных запросов (где запрашивается только часть ресурса) будет использоваться только надежный валидатор (такой как ETag).

На практике, поскольку ресурсы, которые мы защищаем, довольно статичны, а время задержки в одну секунду приемлемо, мы делаем следующее:

  1.  Проверьте, авторизован ли пользователь для доступа к запрошенному ресурсу

         Если это не так, перенаправьте их или отправьте соответствующий ответ 4xx.Мы сгенерируем 404 ответа на запросы, которые выглядят как попытки взлома или явные попытки выполнить конечный запуск системы безопасности.

  2.  Сравните заголовок If-Modified-Since с заголовком Last-Modified, который мы отправили бы (см. Ниже) для строгого равенства

         Если они совпадают, отправьте ответ 304 "Не изменено" и завершите обработку страницы

  3.  Создайте заголовок с последним изменением, используя время изменения запрошенного ресурса

        Посмотрите формат даты HTTP в RFC 2616

  4.  Отправьте заголовок и содержимое ресурса вместе с соответствующим типом содержимого

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

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

что касается управления кэшем:

Вам не нужно беспокоиться о контроле кэша при подаче, за исключением установки для него разумного значения.По сути, он сообщает браузеру и другим нижестоящим объектам (таким как прокси) максимальное время, которое должно пройти до истечения времени ожидания кэша.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top