С очень простой семантикой кэширования: если параметры одинаковы (и URL, конечно, одинаков), то это хит. Это возможно? Рекомендуемые?
С очень простой семантикой кэширования: если параметры одинаковы (и URL, конечно, одинаков), то это хит. Это возможно? Рекомендуемые?
Ответы:
Соответствующий RFC 2616 в разделе 9.5 (POST) позволяет кэшировать ответ на сообщение POST, если вы используете соответствующие заголовки.
Ответы на этот метод не могут быть кэшированы, если ответ не включает в себя соответствующие поля заголовка Cache-Control или Expires. Однако ответ 303 (см. «Другое») может быть использован для того, чтобы указать пользовательскому агенту извлечь кэшируемый ресурс.
Обратите внимание, что тот же RFC прямо указывает в разделе 13 (Кэширование в HTTP), что кеш должен сделать недействительным соответствующий объект после запроса POST .
Некоторые методы HTTP ДОЛЖНЫ приводить к тому, что кеш делает объект недействительным. Это либо объект, на который ссылается Request-URI, либо заголовки Location или Content-Location (если есть). Эти методы:
- PUT - DELETE - POST
Мне не ясно, как эти спецификации могут позволить значимое кэширование.
Это также отражено и уточнено в RFC 7231 (Раздел 4.3.3.), Который устарел в RFC 2616.
Ответы на запросы POST кешируются только в том случае, если они содержат
явную информацию о свежести (см. Раздел 4.2.1 [RFC7234]).
Однако POST-кеширование широко не применяется. В случаях, когда исходный сервер желает, чтобы клиент мог кэшировать результат POST таким образом, который может быть повторно использован последующим GET, исходный сервер МОЖЕТ отправить ответ 200 (ОК), содержащий результат и Content-Location поле заголовка, которое имеет то же значение, что и эффективный URI запроса POST (раздел 3.1.4.2).
В соответствии с этим, результат кэшированного POST (если эта способность указана сервером) может впоследствии использоваться как результат запроса GET для того же URI.
Согласно RFC 2616, раздел 9.5:
«Ответы на метод POST не кешируются, ЕСЛИ ответ не содержит соответствующих полей заголовка Cache-Control или Expires».
Таким образом, ДА, вы можете кэшировать ответ на запрос POST, но только если он приходит с соответствующими заголовками. В большинстве случаев вы не хотите кэшировать ответ. Но в некоторых случаях - например, если вы не сохраняете какие-либо данные на сервере - это вполне уместно.
Обратите внимание, однако, что многие браузеры, включая текущий Firefox 3.0.10, не будут кэшировать POST-ответ независимо от заголовков. IE ведет себя умнее в этом отношении.
Теперь я хочу прояснить некоторую путаницу в отношении RFC 2616 S. 13.10. Метод POST для URI не «лишает законной силы ресурс для кэширования», как некоторые из них заявили здесь. Это делает ранее кэшированную версию этого URI устаревшей, даже если его заголовки управления кешем указывали свежесть большей продолжительности.
GET
и POST
запросов. Если вы находитесь в кеш-памяти между клиентом и сервером, вы видите GET /foo
и кешируете ответ. Затем вы увидите, что от POST /foo
вас требуется сделать недействительным кэшированный ответ, GET /foo
даже если в POST
ответ не включены какие-либо заголовки элемента управления кэшем, поскольку они представляют собой один и тот же URI , поэтому следующий GET /foo
должен будет выполнить повторную проверку, даже если исходные заголовки указывают, что кэш все еще будет в прямом эфире (если вы не видели POST /foo
просьбу)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
, Какой смысл в таком API POST?
В общем и целом:
В основном POST не является идемпотентной операцией . Таким образом, вы не можете использовать его для кэширования. GET должен быть идемпотентной операцией, поэтому он обычно используется для кэширования.
Пожалуйста, смотрите раздел 9.1 HTTP 1.1 RFC 2616 S. 9.1 .
Кроме семантики метода GET:
Сам метод POST семантически предназначен для публикации чего-либо на ресурсе. POST не может быть кэширован, потому что если вы делаете что-то один раз против двух против трех раз, то вы каждый раз изменяете ресурс сервера. Каждый запрос имеет значение и должен быть доставлен на сервер.
Сам метод PUT семантически предназначен для размещения или создания ресурса. Это идемпотентная операция, но она не будет использоваться для кэширования, поскольку в это время могла произойти УДАЛЕНИЕ.
Сам метод DELETE семантически предназначен для удаления ресурса. Это идемпотентная операция, но она не будет использоваться для кэширования, поскольку в это время мог произойти PUT.
Что касается кэширования на стороне клиента:
Веб-браузер всегда будет перенаправлять ваш запрос, даже если у него есть ответ от предыдущей операции POST. Например, вы можете отправлять электронные письма с Gmail через пару дней. Они могут иметь одинаковую тему и текст, но оба сообщения должны быть отправлены.
Что касается кеширования прокси:
Прокси-сервер HTTP, который пересылает ваше сообщение на сервер, никогда не будет кэшировать ничего, кроме запроса GET или HEAD.
Что касается кэширования сервера:
Сервер по умолчанию не будет автоматически обрабатывать запрос POST, проверяя свой кэш. Но, конечно, запрос POST может быть отправлен в ваше приложение или надстройку, и вы можете иметь свой собственный кеш, который вы читаете, когда параметры совпадают.
Аннулирование ресурса:
Проверка HTTP 1.1 RFC 2616 S. 13.10 показывает, что метод POST должен сделать недействительным ресурс для кэширования.
Если вы кешируете POST-ответ, он должен быть в направлении веб-приложения. Это то, что подразумевается под «ответами на этот метод, которые нельзя кэшировать, если ответ не включает в себя соответствующие поля заголовка Cache-Control или Expires».
Можно смело предположить, что приложение, которое знает, являются ли результаты POST идемпотентными, решает, добавлять ли необходимые и правильные заголовки управления кэшем. Если присутствуют заголовки, предлагающие разрешить кэширование, приложение сообщает вам, что POST на самом деле является супер-GET; что использование POST требовалось только из-за количества ненужных и не относящихся к делу (из-за использования URI в качестве ключа кэша) данных, необходимых для выполнения идемпотентной операции.
Следующие GET могут быть поданы из кэша в соответствии с этим предположением.
Приложение, которое не может прикрепить необходимые и правильные заголовки для разграничения между кэшируемыми и не кэшируемыми ответами POST, является ошибочным для любых неверных результатов кэширования.
Тем не менее, каждый POST, который попадает в кэш, требует проверки с использованием условных заголовков. Это необходимо для обновления содержимого кэша, чтобы результаты POST не отражались в ответах на запросы до тех пор, пока не истечет время жизни объекта.
Марк Ноттингем проанализировал, когда возможно кэшировать ответ POST. Обратите внимание, что последующие запросы, которые хотят использовать преимущества кэширования, должны быть запросами GET или HEAD. Смотрите также http семантику
POST не имеют дело с представлениями идентифицированного состояния, 99 раз из 100. Однако, есть один случай, когда это происходит; когда сервер делает все возможное, чтобы сказать, что этот ответ POST является представлением его URI, путем установки заголовка Content-Location, который совпадает с URI запроса. Когда это происходит, ответ POST подобен ответу GET на тот же URI; его можно кэшировать и использовать повторно, но только для будущих запросов GET.
Если вам интересно, можете ли вы кешировать почтовый запрос и попытаться найти ответ на этот вопрос, скорее всего, у вас ничего не получится. При поиске "запроса кеша" первым результатом является вопрос StackOverflow.
Ответы представляют собой запутанную смесь того, как кэширование должно работать, как кэширование работает в соответствии с RFC, как кэширование должно работать в соответствии с RFC, и как кэширование работает на практике. Давайте начнем с RFC, пройдемся по демонстрации того, как на самом деле работает браузер, а затем поговорим о CDN, GraphQL и других проблемных областях.
Согласно RFC, запросы POST должны сделать кеш недействительным:
13.10 Invalidation After Updates or Deletions
..
Some HTTP methods MUST cause a cache to invalidate an entity. This is
either the entity referred to by the Request-URI, or by the Location
or Content-Location headers (if present). These methods are:
- PUT
- DELETE
- POST
Этот язык предполагает, что запросы POST не кэшируются, но это не так (в данном случае). Кэш недействителен только для ранее сохраненных данных. RFC (кажется) явно разъясняет, что да, вы можете кэшировать POST
запросы:
9.5 POST
..
Responses to this method are not cacheable, unless the response
includes appropriate Cache-Control or Expires header fields. However,
the 303 (See Other) response can be used to direct the user agent to
retrieve a cacheable resource.
Несмотря на этот язык, установка Cache-Control
не должна кэшировать последующие POST
запросы к тому же ресурсу. POST
запросы должны быть отправлены на сервер:
13.11 Write-Through Mandatory
..
All methods that might be expected to cause modifications to the
origin server's resources MUST be written through to the origin
server. This currently includes all methods except for GET and HEAD.
A cache MUST NOT reply to such a request from a client before having
transmitted the request to the inbound server, and having received a
corresponding response from the inbound server. This does not prevent
a proxy cache from sending a 100 (Continue) response before the
inbound server has sent its final reply.
Как это имеет смысл? Ну, вы не кешируете POST
запрос, вы кешируете ресурс.
Тело ответа POST может быть кэшировано только для последующих запросов GET к тому же ресурсу. Установите заголовок Location
or Content-Location
в ответе POST, чтобы указать, какой ресурс представляет тело. Таким образом, единственный технически верный способ кэширования POST-запроса - последующие GET для того же ресурса.
Правильный ответ:
Хотя RFC допускает кэширование запросов к одному и тому же ресурсу, на практике браузеры и CDN не реализуют это поведение и не позволяют кэшировать POST-запросы.
Источники:
Приведем следующий пример приложения JavaScript (index.js):
const express = require('express')
const app = express()
let count = 0
app
.get('/asdf', (req, res) => {
count++
const msg = `count is ${count}`
console.log(msg)
res
.set('Access-Control-Allow-Origin', '*')
.set('Cache-Control', 'public, max-age=30')
.send(msg)
})
.post('/asdf', (req, res) => {
count++
const msg = `count is ${count}`
console.log(msg)
res
.set('Access-Control-Allow-Origin', '*')
.set('Cache-Control', 'public, max-age=30')
.set('Content-Location', 'http://localhost:3000/asdf')
.set('Location', 'http://localhost:3000/asdf')
.status(201)
.send(msg)
})
.set('etag', false)
.disable('x-powered-by')
.listen(3000, () => {
console.log('Example app listening on port 3000!')
})
И приведенный ниже пример веб-страницы (index.html):
<!DOCTYPE html>
<html>
<head>
<script>
async function getRequest() {
const response = await fetch('http://localhost:3000/asdf')
const text = await response.text()
alert(text)
}
async function postRequest(message) {
const response = await fetch(
'http://localhost:3000/asdf',
{
method: 'post',
body: { message },
}
)
const text = await response.text()
alert(text)
}
</script>
</head>
<body>
<button onclick="getRequest()">Trigger GET request</button>
<br />
<button onclick="postRequest('trigger1')">Trigger POST request (body 1)</button>
<br />
<button onclick="postRequest('trigger2')">Trigger POST request (body 2)</button>
</body>
</html>
Установите NodeJS, Express и запустите приложение JavaScript. Откройте веб-страницу в вашем браузере. Попробуйте несколько разных сценариев для проверки поведения браузера:
Это показывает, что, хотя вы можете установить заголовки Cache-Control
и Content-Location
ответа, нет никакого способа сделать браузер кэшировать HTTP-запрос POST.
Поведение браузера не настраивается, но если вы не браузер, вы не обязательно связаны правилами RFC.
Если вы пишете код приложения, ничто не мешает вам явно кэшировать POST-запросы (псевдокод):
if (cache.get('hello')) {
return cache.get('hello')
} else {
response = post(url = 'http://somewebsite/hello', request_body = 'world')
cache.put('hello', response.body)
return response.body
}
CDN, прокси и шлюзы не обязательно должны следовать RFC. Например, если вы используете Fastly в качестве CDN, Fastly позволяет вам писать собственную логику VCL для кэширования POST-запросов .
Должен ли ваш POST-запрос кэшироваться или нет, зависит от контекста.
Например, вы можете запросить Elasticsearch или GraphQL, используя POST, если ваш базовый запрос идемпотентен. В этих случаях может иметь или не иметь смысла кэшировать ответ в зависимости от варианта использования.
В RESTful API запросы POST обычно создают ресурс и не должны кэшироваться. Это также понимание RFC POST, что это не идемпотентная операция.
Если вы используете GraphQL и вам требуется HTTP-кэширование в CDN и браузерах, подумайте, соответствует ли отправка запросов методом GET вашим требованиям вместо POST . В качестве предостережения, разные браузеры и CDN могут иметь разные ограничения длины URI, но списки надежных рабочих мест (белый список запросов), как лучший метод для внешних приложений GraphQL, могут сократить URI.
Если это то, что на самом деле не меняет данные на вашем сайте, это должен быть запрос GET. Даже если это форма, вы все равно можете установить ее как запрос на получение. Хотя, как отмечают другие, вы можете кэшировать результаты POST, это не будет иметь смысловой смысл, потому что POST по определению меняет данные.
В Firefox 27.0 и httpfox 19 мая 2014 года я увидел одну строчку этого: 00: 03: 58.777 0,488 657 (393) POST (кэш) text / html https://users.jackiszhp.info/S4UP
Очевидно, что ответ метода post кэшируется, и он также находится в https. Невероятно!
POST используется в Ajax с сохранением состояния. Возврат кэшированного ответа для POST разрушает канал связи и побочные эффекты при получении сообщения. Это очень, очень плохо. Это также настоящая боль, чтобы выследить. Настоятельно рекомендуется против.
Тривиальным примером может служить сообщение о том, что в качестве побочного эффекта выплачивается ваша зарплата в размере 10 000 долларов США на текущей неделе. Вы не хотите, чтобы получить "ОК, это прошло!" страница назад, которая была кеширована на прошлой неделе. Другие, более сложные случаи из реальной жизни приводят к аналогичной веселости.