Я запутался по поводу кеширования HTTP - PullRequest
13 голосов
/ 11 января 2009

Я думал о пакетном чтении и записи в среде RESTful и думаю, что пришел к выводу, что у меня есть более широкие вопросы о HTTP-кэшировании. (Ниже я использую запятые (",") для разделения нескольких идентификаторов записей, но эта деталь не относится к обсуждению.)

Я начал с этой проблемы:

1. Один GET признан недействительным при пакетном обновлении

GET /farms/123         # get info about Old MacDonald's Farm
PUT /farms/123,234,345 # update info on Old MacDonald's Farm and some others
GET /farms/123

Как сервер кэширования между клиентом и сервером Farms узнает, что его кэш-память /farms/123 становится недействительной, когда он видит PUT?

Тогда я понял, что это тоже проблема:

2. Пакетное GET признано недействительным при однократном (или пакетном) обновлении

GET /farms/123,234,345 # get info about a few farms
PUT /farms/123         # update Old MacDonald's Farm
GET /farms/123,234,345

Откуда кэш узнает, что аннулирует множественную ферму GET, когда видит, что PUT проходит?

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

3. Одиночный GET признан недействительным в результате обновления связанной записи

GET /farms/123   # get info about Old MacDonald's Farm
PUT /farmers/987 # Old MacDonald sells his farm and buys another one
GET /farms/123

Как кэш узнает, что делает GET недействительным, когда видит, что PUT проходит?

Даже если вы измените модели на более RESTful, используя модели отношений, вы получите ту же проблему:

GET    /farms/123           # get info about Old MacDonald's Farm
DELETE /farm_ownerships/456 # Old MacDonald sells his farm...
POST   /farm_ownerships     # and buys another one
GET    /farms/123

В обеих версиях # 3 первый GET должен возвращать что-то вроде (в JSON):

farm: {
  id: 123,
  name: "Shady Acres",
  size: "60 acres",
  farmer_id: 987
}

И второй GET должен вернуть что-то вроде:

farm: {
  id: 123,
  name: "Shady Acres",
  size: "60 acres",
  farmer_id: null
}

Но это не может! Даже если вы правильно используете ETag s. Вы не можете ожидать, что сервер кэширования будет проверять содержимое в течение ETag с - содержимое может быть зашифровано. И вы не можете ожидать, что сервер уведомит кэши о том, что записи должны быть признаны недействительными - кэши не регистрируются на серверах.

Так есть ли заголовки, которые мне не хватает? Вещи, которые указывают, что кэш должен делать HEAD перед любыми GET с для определенных ресурсов? Я полагаю, что я мог бы справиться с двойными запросами для каждого ресурса, если бы я мог сообщать кешам, какие ресурсы, вероятно, будут часто обновляться.

А как насчет проблемы, когда один кеш получает PUT и знает, что его кэш недействителен, а другой не видит его?

Ответы [ 5 ]

6 голосов
/ 11 января 2009

Серверы кэширования должны сделать недействительной сущность, на которую ссылается URI, при получении PUT (но, как вы заметили, это не охватывает все случаи).

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

Это все еще очень сложный вопрос, и на самом деле он все еще работает (например, см. http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p6-cache-05.txt)

Кэширование в прокси-серверах на самом деле не применяется, если контент зашифрован (по крайней мере, с помощью SSL), поэтому это не должно быть проблемой (хотя это может быть проблемой на клиенте).

2 голосов
/ 11 января 2009

Протокол HTTP поддерживает тип запроса, называемый «If-Modified-Since», который в основном позволяет серверу кэширования запрашивать у веб-сервера, изменился ли элемент. Протокол HTTP также поддерживает заголовки «Cache-Control» внутри ответов HTTP-сервера, которые сообщают серверам кеша, что делать с контентом (например, никогда не кэшировать это или считать, что срок его действия истекает через 1 день и т. Д.).

Также вы упомянули зашифрованные ответы. Кеш-серверы HTTP не могут кешировать SSL, потому что для этого потребуется расшифровать страницы как «человек посередине». Это было бы технически сложно (расшифровать страницу, сохранить ее и повторно зашифровать для клиента), а также нарушить безопасность страницы, вызывая предупреждения «недействительный сертификат» на стороне клиента. Технически возможно, чтобы кеш-сервер делал это, но это вызывает больше проблем, чем решает, и это плохая идея. Я сомневаюсь, что любые серверы кеша на самом деле делают такие вещи.

1 голос
/ 11 января 2009

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

1 голос
/ 11 января 2009

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

Если у вас было:

GET /farm/123
POST /farm_update/123

Вы можете использовать заголовок Content-Location, чтобы указать, что второй запрос изменил первый. AFAIK, вы не можете сделать это с несколькими URI, и я не проверял, работает ли это вообще в популярных клиентах.

Решением является быстрое истечение срока действия страниц и обработка If-Modified-Since или E-Tag со статусом 304 Not Modified.

0 голосов
/ 11 января 2009

В ответ: SoapBox ответ:

  1. Я думаю If-Modified-Since - это двухэтапный GET, который я предложил в конце моего вопроса. Это похоже на правильное решение, когда контент большой (т. Е. Когда стоимость удвоения количества запросов и, следовательно, накладных расходов преодолевается за счет отказа от повторной отправки контента. Это не так в моем примере с фермами, поскольку информация о каждой ферме коротка.)

  2. Совершенно разумно создать систему, которая отправляет зашифрованный контент по незашифрованному (HTTP) каналу. Представьте себе сценарий сервис-ориентированной архитектуры, в которой обновления происходят нечасто и GET с (а) часто, (b) должны быть чрезвычайно быстрыми и (с) должны быть зашифрованы. Вы должны создать сервер, для которого требуется заголовок FROM (или, что то же самое, ключ API в параметрах запроса), и отправлять асимметрично зашифрованную версию содержимого для запрашивающей стороны. Асимметричное шифрование медленное, но при правильном кэшировании превосходит комбинированное рукопожатие SSL (асимметричное шифрование) и симметричное шифрование содержимого. Добавление кэша перед этим сервером значительно ускорит GET с.

  3. Сервер кэширования может разумно кэшировать GET HTTPS в течение короткого периода времени. Мой банк может установить контроль кэша примерно на 5 минут на домашней странице моего аккаунта и последних транзакциях. Я не очень-то склонен тратить много времени на сайте, поэтому сессии не будут очень длинными, и я, вероятно, в конечном итоге попаду на главную страницу своего аккаунта несколько раз, пока я ищу тот чек, который я недавно отправил SnorgTees .

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