Как узнать, когда отправить ответ 304 Не модифицировано - PullRequest
10 голосов
/ 07 августа 2008

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

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

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

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


А как насчет заголовка управления кешем? Могут ли различные возможные значения, которые влияют на то, что вы отправляете клиенту (а именно, max-age), или должны соблюдаться только в случае изменения?

Ответы [ 5 ]

8 голосов
/ 07 августа 2008

Вот как я это реализовал. Код работал чуть больше года и с несколькими браузерами, поэтому я думаю, что он довольно надежный. Это основано на 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, напишите другой вопрос, и я найду некоторый код, который также это делает. НТН!

4 голосов
/ 09 августа 2008

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

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

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

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

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

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

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

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

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

3 голосов
/ 07 августа 2008

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

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

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

2 голосов
/ 13 октября 2009

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

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

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

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

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

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

  3. Создание последнего измененного заголовка с использованием времени модификации запрошенного ресурса

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

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

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

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

1 голос
/ 07 августа 2008

относительно контроля кеша:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...