С очень простой семантикой кэширования: если параметры совпадают (и URL тот же, конечно), то это хит. Это возможно? Рекомендуемые?
Можно ли кэшировать методы POST в HTTP?
Ответы (9)
Соответствующий RFC 2616 в разделе 9.5 (POST) позволяет кэшировать ответ в сообщение POST, если вы используете соответствующие заголовки.
Ответы на этот метод не кэшируются, если ответ не включает соответствующие поля заголовка Cache-Control или Expires. Тем не менее, ответ 303 (см. Другое) может быть использован для указания агенту пользователя получить кэшируемый ресурс.
Обратите внимание, что в разделе 13 (Кэширование в HTTP) того же RFC прямо указано, что кэш должен аннулировать соответствующий объект после запроса 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 (OK), содержащий результат и 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
)
- person Stephen Connolly; 28.09.2018
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. В чем тогда вообще смысл такого POST API?
- person Siddhartha; 07.06.2020
В целом:
По сути, POST не является идемпотентной операцией. Таким образом, вы не можете использовать его для кэширования. GET должна быть идемпотентной операцией, поэтому она обычно используется для кэширования.
См. раздел 9.1 HTTP 1.1 RFC 2616 S. 9.1 а>.
Кроме семантики метода GET:
Сам метод POST семантически предназначен для публикации чего-либо в ресурсе. POST нельзя кэшировать, потому что если вы делаете что-то один раз, два раза или три раза, то вы каждый раз изменяете ресурс сервера. Каждый запрос имеет значение и должен быть доставлен на сервер.
Сам метод PUT семантически предназначен для размещения или создания ресурса. Это идемпотентная операция, но она не будет использоваться для кэширования, поскольку за это время могло произойти DELETE.
Сам метод DELETE семантически предназначен для удаления ресурса. Это идемпотентная операция, но она не будет использоваться для кэширования, поскольку за это время могла произойти PUT.
Что касается кэширования на стороне клиента:
Веб-браузер всегда будет пересылать ваш запрос, даже если у него есть ответ от предыдущей операции POST. Например, вы можете отправлять электронные письма с помощью Gmail с разницей в пару дней. У них может быть одна и та же тема и тело, но оба письма должны быть отправлены.
Относительно кеширования прокси:
Прокси-сервер HTTP, который пересылает ваше сообщение на сервер, никогда не будет кэшировать ничего, кроме запроса GET или HEAD.
Относительно кэширования сервера:
Сервер по умолчанию не будет автоматически обрабатывать запрос POST, проверяя свой кеш. Но, конечно, запрос POST может быть отправлен вашему приложению или надстройке, и вы можете иметь свой собственный кеш, который вы читаете, когда параметры совпадают.
Объявление ресурса недействительным:
Проверка HTTP 1.1 RFC 2616 S. 13.10 показывает, что метод POST должен аннулировать ресурс для кэширования.
REST
— POST не idemp. -› кэшировать нельзя, HTTP
- POST можно кэшировать. Выбирайте в зависимости от того, придерживаетесь ли вы REST или просто используете HTTP в качестве протокола обмена данными. Оба правы в своих областях.
- person skryvets; 03.07.2020
Если вы задаетесь вопросом, можете ли вы кэшировать запрос на публикацию, и пытаетесь найти ответ на этот вопрос, скорее всего, у вас ничего не получится. При поиске «кэшировать почтовый запрос» первым результатом является этот вопрос StackOverflow.
Ответы представляют собой запутанную смесь того, как должно работать кэширование, как кэширование работает в соответствии с RFC, как кэширование должно работать в соответствии с RFC и как кэширование работает на практике. Давайте начнем с RFC, пройдем демонстрацию того, как на самом деле работает браузер, а затем поговорим о CDN, GraphQL и других проблемных областях.
RFC 2616
Согласно 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
или Content-Location
в ответе POST, чтобы сообщить, какой ресурс представляет тело. Таким образом, единственный технически допустимый способ кэширования POST-запроса — это последующие GET-запросы к тому же ресурсу.
Правильный ответ оба:
- «да, RFC позволяет вам кэшировать POST-запросы для последующих GET к тому же ресурсу»
- «нет, RFC не позволяет вам кэшировать запросы POST для последующих POST, потому что POST не является идемпотентным и должен быть записан на сервер»
Хотя RFC позволяет кэшировать запросы к одному и тому же ресурсу, на практике браузеры и CDN не реализуют такое поведение и не позволяют кэшировать POST-запросы.
Источники:
- https://tools.ietf.org/html/rfc2616#section-13 HTTP/1.1 RFC
- https://www.mnot.net/blog/2012/09/24/caching_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. Откройте веб-страницу в браузере. Попробуйте несколько разных сценариев, чтобы проверить поведение браузера:
- При нажатии «Запустить запрос GET» каждый раз отображается одно и то же «счетчик» (работает кэширование HTTP).
- Нажатие «Запустить запрос POST» каждый раз запускает другой счетчик (кеширование HTTP для POST не работает).
- Щелчок «Инициировать запрос GET», «Инициировать запрос POST» и «Инициировать запрос GET» показывает, что запрос POST делает недействительным кеш запроса GET.
- Нажав «Запустить запрос POST», а затем «Запустить запрос GET», вы увидите, что браузеры не будут кэшировать запросы POST для последующих запросов GET, даже если это разрешено RFC.
Это показывает, что, хотя вы можете установить заголовки ответов Cache-Control
и Content-Location
, нет никакого способа заставить браузер кэшировать запрос HTTP POST.
Должен ли я следовать RFC?
Поведение браузера не настраивается, но если вы не браузер, вы не обязательно связаны правилами 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-запросы?
Должен ли ваш POST-запрос кэшироваться или нет, зависит от контекста.
Например, вы можете запросить Elasticsearch или GraphQL с помощью POST, если ваш базовый запрос является идемпотентным. В этих случаях может иметь или не иметь смысл кэшировать ответ в зависимости от варианта использования.
В RESTful API запросы POST обычно создают ресурс и не должны кэшироваться. Это также понимание RFC о том, что POST не является идемпотентной операцией.
ГрафQL
Если вы используете GraphQL и вам требуется кэширование HTTP в CDN и браузерах, рассмотрите возможность отправки запросов с использованием метод GET соответствует вашим требованиям вместо POST. Обратите внимание, что разные браузеры и CDN могут иметь разные ограничения длины URI, но списки безопасных операций (белый список запросов), рекомендуемый для внешних производственных приложений GraphQL, могут сокращать URI.
Если вы кэшируете ответ POST, он должен направляться веб-приложению. Это то, что подразумевается под «Ответы на этот метод не кэшируются, если ответ не включает соответствующие поля заголовка Cache-Control или Expires».
Можно с уверенностью предположить, что приложение, которое знает, являются ли результаты POST идемпотентными, решает, присоединять ли необходимые и правильные заголовки управления кешем. Если присутствуют заголовки, предлагающие кэширование, приложение сообщает вам, что POST на самом деле является супер-GET; что использование POST требовалось только из-за количества ненужных и нерелевантных (для использования URI в качестве ключа кэша) данных, необходимых для выполнения идемпотентной операции.
При таком предположении следующие GET могут быть обслужены из кеша.
Приложение, которое не может прикрепить необходимые и правильные заголовки, чтобы различать кешируемые и некэшируемые ответы POST, является причиной любых недопустимых результатов кэширования.
Тем не менее, каждый POST, попадающий в кеш, требует проверки с использованием условных заголовков. Это необходимо для обновления содержимого кеша, чтобы результаты POST не отражались в ответах на запросы до тех пор, пока не истечет время жизни объекта.
Марк Ноттингем проанализировал, когда можно кэшировать ответ POST. Обратите внимание, что последующие запросы, которые хотят воспользоваться преимуществами кэширования, должны быть запросами GET или HEAD. См. также https://tools.ietf.org/html/rfc7231#section-4.3.3.
POST не имеют дело с представлениями идентифицированного состояния, 99 раз из 100. Однако есть один случай, когда это происходит; когда сервер изо всех сил пытается сказать, что этот ответ POST является представлением его URI, устанавливая заголовок Content-Location, который совпадает с URI запроса. Когда это происходит, ответ POST ничем не отличается от ответа GET на тот же URI; его можно кэшировать и использовать повторно, но только для будущих запросов GET.
https://www.mnot.net/blog/2012/09/24/caching_POST.
Если это что-то, что на самом деле не изменяет данные на вашем сайте, это должен быть запрос GET. Даже если это форма, вы все равно можете установить ее как запрос на получение. Хотя, как отмечают другие, вы можете кэшировать результаты POST, это не будет иметь семантического смысла, потому что POST по определению изменяет данные.
С firefox 27.0 и httpfox 19 мая 2014 года я увидел одну строку: 00:03:58.777 0,488 657 (393) POST (Cache) text/html https://users.jackiszhp.info/S4UP
Понятно, что ответ почтового метода кешируется, и он тоже в https. Невероятный!
POST используется в Ajax с отслеживанием состояния. Возврат кэшированного ответа для POST отключает канал связи и побочные эффекты получения сообщения. Это очень очень плохо. Это также настоящая боль, чтобы выследить. Настоятельно рекомендуется против.
Тривиальным примером может быть сообщение, побочным эффектом которого является выплата вашей зарплаты в размере 10 000 долларов США за текущую неделю. Вы НЕ хотите получить "Хорошо, все прошло!" предыдущая страница, которая была кэширована на прошлой неделе. Другие, более сложные случаи из реальной жизни вызывают такое же веселье.