Відповіді:
Відповідний RFC 2616 у розділі 9.5 (POST) дозволяє кешувати відповідь на повідомлення POST, якщо ви використовуєте відповідні заголовки.
Відповіді на цей метод не підлягають кешуванню, якщо тільки відповідь не включає відповідні поля заголовка кеша або закінчується. Однак відповідь 303 (див. Інше) може бути використана для спрямування агента користувача на отримання кешованого ресурсу.
Зауважте, що той самий RFC прямо в розділі 13 (Кешування в HTTP) прямо заявляє, що кеш повинен визнати недійсним відповідний об'єкт після POST- запиту .
Деякі методи HTTP ОБОВ'ЯЗКОВО викликають кеш, щоб визнати об'єкт суттєвим. Це або сутність, на яку посилається URI-запит, або заголовки Місцеположення або Вміст-Місцеположення (якщо вони є). Такими методами є:
- PUT - DELETE - POST
Мені не зрозуміло, як ці технічні характеристики можуть дозволити змістовне кешування.
Це також відображено та уточнено в RFC 7231 (Розділ 4.3.3.), Який застаріває RFC 2616.
Відповіді на POST-запити кешуються лише тоді, коли вони містять
явну інформацію про свіжість (див. Розділ 4.2.1 [RFC7234]).
Однак кешування POST не використовується широко. У випадках, коли сервер-джерело бажає, щоб клієнт міг кешувати результат POST таким чином, який може бути використаний більш пізнім GET, сервер-джерело МОЖЕ надіслати відповідь 200 (ОК), що містить результат та розташування вмісту поле заголовка, яке має те саме значення, що і URI ефективного запиту POST (Розділ 3.1.4.2).
Відповідно до цього, результат кешованого POST (якщо ця здатність вказаний сервером) може бути згодом використаний як результат GET-запиту на той самий URI.
Згідно з розділом 9.5 RFC 2616:
"Відповіді на метод POST не підлягають кеш-пам'яті, ПІДТВІДЧИЙ відповідь включає відповідні поля заголовка кеша або закінчується."
Так, ТАК, ви можете кешувати відповідь на запит 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.
. У чому сенс такого POST API в першу чергу?
Загалом:
В основному POST не є безвідмовною операцією . Тому ви не можете використовувати його для кешування. GET має бути безвідмовною операцією, тому її зазвичай використовують для кешування.
Дивіться розділ 9.1 HTTP 1.1 RFC 2616 S. 9.1 .
Окрім семантики методу GET:
Сам метод POST семантично призначений для публікації чогось на ресурсі. POST неможливо кешувати, оскільки якщо ви робите щось один раз проти двічі проти трьох разів, то ви щоразу змінюєте ресурс сервера. Кожен запит має значення і повинен бути доставлений на сервер.
Сам метод PUT семантично призначений для розміщення або створення ресурсу. Це ідентична операція, але вона не використовуватиметься для кешування, оскільки тим часом DELETE могла статися.
Сам метод DELETE має семантичне значення для видалення ресурсу. Це ідентична операція, але вона не буде використовуватися для кешування, оскільки PUT могла відбутися тим часом.
Щодо кешування на стороні клієнта:
Веб-браузер завжди буде пересилати ваш запит, навіть якщо він має відповідь від попередньої операції POST. Наприклад, ви можете надсилати електронні листи електронною поштою один раз за кілька днів. Вони можуть бути одним і тим же предметом і тілом, але обидва електронні листи слід надсилати.
Щодо кешування проксі:
Проксі-сервер HTTP, який пересилає ваше повідомлення на сервер, ніколи не кешуватиме нічого, крім GET або HEAD-запиту.
Щодо кешування сервера:
Сервер за замовчуванням не автоматично обробляє запит POST, перевіряючи його кеш. Але звичайно, POST-запит може бути надісланий вашій програмі або додатку, і ви можете мати власний кеш, з якого ви читали, коли параметри однакові.
Недійсний ресурс:
Перевірка HTTP 1.1 RFC 2616 S. 13.10 показує, що метод POST повинен визнати недійсним ресурс для кешування.
Якщо ви кешуєте відповідь POST, вона повинна відповідати вказівкам веб-програми. Це означає, що "Відповіді на цей метод не підлягають кеш-пам'яті, якщо тільки відповідь не включає відповідні поля заголовка кеша або закінчується".
Можна з упевненістю припустити, що програма, яка знає, чи є результати POST однозначними, вирішує, додавати чи ні необхідні та належні заголовки кешування керування чи ні. Якщо заголовки, які передбачають кешування, є, програма заявляє вам, що POST насправді є супер-GET; що використання POST потрібно було лише через кількість непотрібних та неактуальних (для використання URI як кеш-ключа) даних, необхідних для виконання операції ідентифікації.
Наступні GET можуть подаватися з кешу за цим припущенням.
Додаток, який не в змозі приєднати необхідні та правильні заголовки для розмежування між керованими та нехабільними відповідями POST, винен у будь-яких недійсних результатах кешування.
Однак, для кожного POST, який потрапляє в кеш, потрібна перевірка, використовуючи умовні заголовки. Це потрібно для того, щоб оновити вміст кешу, щоб уникнути того, щоб результати POST не відображалися у відповідях на запити до закінчення терміну дії об'єкта.
Марк Ноттінгем проаналізував, коли можливо кешувати відповідь POST. Зауважте, що наступні запити, які хочуть скористатися кешуванням, повинні бути GET або HEAD-запитами. Дивіться також http семантику
POST не розглядають уявлення про визначений стан, 99 разів із 100. Однак є один випадок, коли це відбувається; коли сервер виходить зі шляху, щоб сказати, що ця відповідь POST є відображенням його URI, встановивши заголовок Content-Location, такий самий, як URI запиту. Коли це відбувається, відповідь POST є подібно до отримання відповіді на той самий 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
або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. Наприклад, якщо ви швидко використовуєте свій CDN, швидко дозволяє записати власну логіку VCL для кешування запитів POST .
Потрібно кешувати ваш запит POST чи ні, залежить від контексту.
Наприклад, ви можете запитувати Elasticsearch або GraphQL за допомогою POST, де ваш базовий запит є ідентичним. У цих випадках може або не має сенсу кешувати відповідь залежно від випадку використання.
У API RESTful, 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 (Кеш) текст / html https://users.jackiszhp.info/S4UP
Очевидно, що відповідь методу публікації є кешованою, і вона також є в https. Неймовірно!
POST використовується у великому Ajax. Повернення кешованої відповіді для POST перетворює канал зв’язку та побічні ефекти прийому повідомлення. Це дуже-дуже погано. Це також справжній біль відстежити. Настійно рекомендується проти.
Тривіальним прикладом може бути повідомлення про те, що в якості побічного ефекту виплачуєте вашу зарплату 10 000 доларів на поточному тижні. Ви НЕ хочете отримати "ОК, це пройшло!" повернення сторінки, кешоване минулого тижня. Інші, більш складні реальні випадки призводять до подібної веселості.