Я запутался в кешировании HTTP
Я думал о пакетных чтениях и записи в среде RESTful, и я думаю, что пришел к пониманию, что у меня есть более широкие вопросы о кешировании HTTP. (Ниже я использую запятые ( "," ), чтобы разграничить несколько идентификаторов записи, но эта деталь не относится к обсуждению.)
Я начал с этой проблемы:
1. Единый GET
недействительный пакетным обновлением
GET /farms/123 # get info about Old MacDonald Farm
PUT /farms/123,234,345 # update info on Old MacDonald 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 Farm
GET /farms/123,234,345
Как известно кешу об аннулировании многоуровневого GET
, когда он видит, что PUT идет?
Итак, я понял, что проблема была действительно просто с пакетными операциями. Тогда я понял, что любая связь может вызвать подобную проблему. Пусть говорят, что у фермы есть нуль или один владелец, а владелец может иметь нуль или одну ферму.
3. Единый GET
недействителен обновлением соответствующей записи
GET /farms/123 # get info about Old MacDonald 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 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
соответствующим образом. Вы не можете ожидать, что сервер кэширования проверит содержимое для ETag
- содержимое может быть зашифровано. И вы не можете ожидать, что сервер уведомит кэши, что записи должны быть недействительными - кэши не регистрируются на серверах.
Так есть ли заголовки, которые мне не хватает? Вещи, указывающие на кеш, должны делать HEAD
перед любым GET
для определенных ресурсов? Я полагаю, что я мог бы жить с двойными запросами на каждый ресурс, если я могу сказать кэшам, что ресурсы, вероятно, будут часто обновляться.
А как насчет проблемы с одним кешем, получающим PUT
, и зная, как аннулировать его кеш, а другой - не видеть?
Ответы
Ответ 1
Кэш-серверы должны аннулировать объект, на который указывает URI при получении PUT (но, как вы заметили, это не распространяется на все случаи).
Помимо этого вы можете использовать заголовки управления кешем в своих ответах для ограничения или предотвращения кеширования и попытаться обработать заголовки запросов, которые спрашивают, был ли изменен URI с момента последнего получения.
Это по-прежнему очень сложная проблема и на самом деле все еще работает (например, см. http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p6-cache-05.txt)
Кэширование внутри прокси-серверов действительно не применяется, если содержимое зашифровано (по крайней мере, с помощью SSL), поэтому это не должно быть проблемой (все же может быть проблема на клиенте).
Ответ 2
Протокол HTTP поддерживает тип запроса, называемый "If-Modified-Since", который в основном позволяет серверу кэширования запрашивать веб-сервер, если элемент был изменен. Протокол HTTP также поддерживает заголовки "Cache-Control" внутри ответов HTTP-сервера, которые сообщают серверам кешей, что делать с контентом (например, никогда не кэшировать это, или считать, что он истекает через 1 день и т.д.).
Также вы упомянули зашифрованные ответы. Кэш-серверы HTTP не могут кэшировать SSL, потому что для этого потребуется, чтобы они расшифровывали страницы как "человека посередине". Это будет технически сложным (расшифровать страницу, сохранить ее и повторно зашифровать для клиента), а также нарушить безопасность страницы, вызывающую предупреждения "недопустимый сертификат" на стороне клиента. Технически возможно иметь кэш-сервер, но это вызывает больше проблем, чем решает, и это плохая идея. Я сомневаюсь, что кэш-серверы действительно делают такие вещи.
Ответ 3
К сожалению, кеширование HTTP основано на точных URI, и вы не можете добиться разумного поведения в своем случае, не заставляя клиентов делать повторную проверку кэширования.
Если у вас было:
GET /farm/123
POST /farm_update/123
Вы можете использовать заголовок Content-Location
, чтобы указать, что второй запрос изменил первый. AFAIK вы не можете сделать это с несколькими URI, и я не проверял, работает ли это вообще у популярных клиентов.
Решение состоит в том, чтобы быстро выполнить печать страниц и обработать If-Modified-Since
или E-Tag
с помощью статуса 304 Not Modified
.
Ответ 4
Вы не можете кэшировать динамический контент (с недостатками), потому что... он динамический.
Ответ 5
В re: SoapBox ответ:
-
Я думаю, что If-Modified-Since
- это двухэтапный GET
, который я предложил в конце моего вопроса. Это похоже на решение "ОК", где контент большой (т.е. Где стоимость удвоения количества запросов и, следовательно, накладные расходы преодолеваются за счет увеличения не пересылаемого контента). Это не так на моем примере ферм, поскольку каждая информация о ферме коротка.)
-
Совершенно разумно создавать систему, которая отправляет зашифрованный контент по незашифрованному (HTTP) каналу. Представьте себе сценарий сервис-ориентированной архитектуры, где обновления нечасты, а GET
(a) часты, (b) должны быть чрезвычайно быстрыми, и (c) необходимо зашифровать. Вы бы создали сервер, для которого требуется заголовок FROM
(или, что то же самое, ключ API в параметрах запроса) и отправляет обратно асимметрично зашифрованную версию содержимого для запрашивающего. Асимметричное шифрование выполняется медленно, но при правильном кэшировании используется комбинированное SSL-подтверждение (асимметричное шифрование) и симметричное шифрование содержимого. Добавление кеша перед этим сервером резко ускорит GET
s.
-
Кэширующий сервер может достаточно быстро кэшировать HTTPS GET в течение короткого периода времени. Мой банк может установить контроль над кешем около 5 минут на моей домашней странице учетной записи и последних транзакциях. Я не очень долго трачу много времени на сайте, поэтому сеансы будут не очень длинными, и я, вероятно, в конечном итоге попаду на главную страницу своей учетной записи несколько раз, пока я ищу эту проверку, которую я недавно отправил SnorgTees.