Jawaban:
RFC 2616 yang sesuai di bagian 9.5 (POST) memungkinkan penyimpanan respons terhadap pesan POST, jika Anda menggunakan header yang sesuai.
Respons terhadap metode ini tidak dapat di-cache, kecuali jika responsnya menyertakan bidang Cache-Control atau Expire header yang sesuai. Namun, respons 303 (Lihat Lainnya) dapat digunakan untuk mengarahkan agen pengguna untuk mengambil sumber daya yang dapat di-cache.
Perhatikan bahwa RFC yang sama menyatakan secara eksplisit di bagian 13 (Caching dalam HTTP) bahwa cache harus membatalkan entitas terkait setelah permintaan POST .
Beberapa metode HTTP HARUS menyebabkan cache untuk membatalkan entitas. Entah ini entitas yang dirujuk oleh Request-URI, atau oleh header Location atau Content-Location (jika ada). Metode-metode ini adalah:
- PUT - DELETE - POST
Tidak jelas bagi saya bagaimana spesifikasi ini dapat memungkinkan caching yang bermakna.
Ini juga tercermin dan dijelaskan lebih lanjut dalam RFC 7231 (Bagian 4.3.3.), Yang menggantikan RFC 2616.
Respons terhadap permintaan POST hanya dapat di-cache ketika mereka menyertakan
informasi kesegaran eksplisit (lihat Bagian 4.2.1 dari [RFC7234]).
Namun, caching POST tidak diterapkan secara luas. Untuk kasus-kasus di mana server asal berharap klien dapat men-cache hasil POST dengan cara yang dapat digunakan kembali oleh GET yang lebih baru, server asal MUNGKIN mengirimkan respons 200 (OK) yang berisi hasil dan Lokasi-Konten bidang header yang memiliki nilai yang sama dengan URI permintaan efektif POST (Bagian 3.1.4.2).
Menurut ini, hasil POST yang di-cache (jika kemampuan ini ditunjukkan oleh server) selanjutnya dapat digunakan sebagai hasil dari permintaan GET untuk URI yang sama.
Menurut RFC 2616 Bagian 9.5:
"Respons terhadap metode POST tidak dapat di-cache, KECUALI responsnya termasuk bidang Cache-Control atau Expires header yang sesuai."
Jadi, YA, Anda bisa menyimpan respons permintaan POST tetapi hanya jika ada header yang sesuai. Dalam kebanyakan kasus, Anda tidak ingin menyimpan tanggapan. Tetapi dalam beberapa kasus - seperti jika Anda tidak menyimpan data apa pun di server - itu sepenuhnya tepat.
Catatan, namun banyak peramban, termasuk Firefox 3.0.10 saat ini, tidak akan menyimpan respons POST terlepas dari header. IE berperilaku lebih pintar dalam hal ini.
Sekarang, saya ingin menjernihkan kebingungan di sini mengenai RFC 2616 S. 13.10. Metode POST pada URI tidak "membatalkan sumber daya untuk caching" seperti yang telah dinyatakan di sini. Itu membuat versi URI yang sebelumnya di-cache basi, bahkan jika header kontrol cache menunjukkan kesegaran durasi yang lebih lama.
GET
dan POST
permintaan URI yang sama . Jika Anda adalah cache yang berada di antara klien dan server, Anda melihat GET /foo
dan Anda menyimpan respons. Selanjutnya Anda melihat POST /foo
maka Anda diharuskan untuk membatalkan respons yang di-cache dari GET /foo
bahkan jika POST
respons tersebut tidak menyertakan header kontrol cache apa pun karena mereka adalah URI yang sama , sehingga berikutnya GET /foo
harus memvalidasi ulang bahkan jika header asli mengindikasikan cache masih akan menjadi live (jika Anda belum melihat POST /foo
permintaan)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. Apa gunanya POST API seperti itu?
Secara keseluruhan:
Pada dasarnya POST bukan operasi idempoten . Jadi Anda tidak bisa menggunakannya untuk caching. GET harus merupakan operasi idempoten, jadi ini biasa digunakan untuk caching.
Silakan lihat bagian 9.1 dari HTTP 1.1 RFC 2616 S. 9.1 .
Selain dari semantik metode GET:
Metode POST itu sendiri secara semantik dimaksudkan untuk memposting sesuatu ke sumber. POST tidak dapat di-cache karena jika Anda melakukan sesuatu sekali vs dua kali vs tiga kali, maka Anda mengubah sumber daya server setiap kali. Setiap permintaan penting dan harus dikirimkan ke server.
Metode PUT itu sendiri secara semantik dimaksudkan untuk menempatkan atau membuat sumber daya. Ini adalah operasi idempoten, tetapi itu tidak akan digunakan untuk caching karena DELETE bisa saja terjadi sementara itu.
Metode DELETE itu sendiri semantik dimaksudkan untuk menghapus sumber daya. Ini adalah operasi idempoten, tetapi itu tidak akan digunakan untuk caching karena PUT bisa saja terjadi sementara itu.
Mengenai caching sisi klien:
Peramban web akan selalu meneruskan permintaan Anda, bahkan jika ada respons dari operasi POST sebelumnya. Misalnya Anda dapat mengirim email dengan gmail yang terpisah beberapa hari. Mereka mungkin subjek dan badan yang sama, tetapi kedua email harus dikirim.
Mengenai caching proxy:
Server HTTP proksi yang meneruskan pesan Anda ke server tidak akan pernah menembolok apa pun selain permintaan GET atau HEAD.
Mengenai caching server:
Server secara default tidak akan secara otomatis menangani permintaan POST melalui pengecekan cache-nya. Tetapi tentu saja permintaan POST dapat dikirim ke aplikasi atau add-in Anda dan Anda dapat memiliki cache sendiri yang Anda baca dari saat parameternya sama.
Memvalidasi sumber daya:
Memeriksa HTTP 1.1 RFC 2616 S. 13.10 menunjukkan bahwa metode POST harus membatalkan sumber daya untuk caching.
Jika Anda melakukan cache respons POST, itu harus sesuai dengan arah aplikasi web. Inilah yang dimaksud dengan "Respons terhadap metode ini tidak dapat di-cachable, kecuali jika responsnya menyertakan bidang Cache-Control atau Expires header yang sesuai."
Orang dapat dengan aman berasumsi bahwa aplikasi, yang mengetahui apakah hasil POST idempoten atau tidak, memutuskan apakah akan memasang header kontrol cache yang diperlukan dan tepat. Jika tajuk yang menyarankan caching diperbolehkan ada, aplikasi memberi tahu Anda bahwa POST, pada kenyataannya, adalah GET-super; bahwa penggunaan POST hanya diperlukan karena jumlah data yang tidak perlu dan tidak relevan (untuk penggunaan URI sebagai kunci cache) yang diperlukan untuk melakukan operasi idempoten.
Mengikuti GET dapat dilayani dari cache dengan asumsi ini.
Aplikasi yang gagal melampirkan tajuk yang diperlukan dan benar untuk membedakan antara respons POST yang tidak dapat ditutup dan tidak bisa dikirim adalah kesalahan untuk setiap hasil caching yang tidak valid.
Yang mengatakan, setiap POST yang mengenai cache memerlukan validasi menggunakan header kondisional. Ini diperlukan untuk me-refresh konten cache untuk menghindari agar hasil POST tidak tercermin dalam respons terhadap permintaan hingga setelah masa hidup objek berakhir.
Mark Nottingham telah menganalisis kapan layak untuk menembaki respons POST. Perhatikan bahwa permintaan berikutnya yang ingin memanfaatkan caching haruslah GET atau permintaan HEAD. Lihat juga semantik http
POST tidak berurusan dengan representasi negara yang teridentifikasi, 99 kali dari 100. Namun, ada satu kasus di mana ia melakukannya; ketika server keluar dari cara untuk mengatakan bahwa respons POST ini adalah representasi dari URI-nya, dengan mengatur header Konten-Lokasi yang sama dengan URI permintaan. Ketika itu terjadi, respons POST sama seperti respons GET untuk URI yang sama; itu bisa di-cache dan digunakan kembali - tetapi hanya untuk permintaan GET di masa depan.
Jika Anda bertanya-tanya apakah Anda dapat men-cache permintaan posting, dan mencoba meneliti jawaban untuk pertanyaan itu, Anda kemungkinan tidak akan berhasil. Saat mencari "permintaan posting cache" hasil pertama adalah pertanyaan StackOverflow ini.
Jawabannya adalah campuran bingung tentang bagaimana caching harus bekerja, bagaimana caching bekerja sesuai dengan RFC, bagaimana caching harus bekerja sesuai dengan RFC, dan bagaimana caching bekerja dalam praktik. Mari kita mulai dengan RFC, telusuri demonstrasi tentang bagaimana sebenarnya browser berfungsi, kemudian bicarakan CDN, GraphQL, dan bidang lain yang menjadi perhatian.
Per RFC, permintaan POST harus membatalkan cache:
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
Bahasa ini menunjukkan bahwa permintaan POST tidak dapat di-cache, tetapi itu tidak benar (dalam hal ini). Cache hanya tidak valid untuk data yang disimpan sebelumnya. RFC (tampaknya) secara eksplisit menjelaskan bahwa ya, Anda dapat men-cache POST
permintaan:
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.
Terlepas dari bahasa ini, pengaturan Cache-Control
tidak boleh menembolok POST
permintaan berikutnya ke sumber yang sama. POST
permintaan harus dikirim ke server:
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.
Bagaimana itu masuk akal? Nah, Anda tidak menembaki POST
permintaan, Anda men-cache sumber daya.
Badan respons POST hanya bisa di-cache untuk permintaan GET berikutnya ke sumber yang sama. Setel tajuk Location
atau Content-Location
di respons POST untuk mengomunikasikan sumber daya yang diwakili oleh badan. Jadi satu-satunya cara yang valid secara teknis untuk men-cache permintaan POST, adalah untuk mendapatkan GET berikutnya ke sumber daya yang sama.
Jawaban yang benar adalah keduanya:
Meskipun RFC memungkinkan untuk caching permintaan ke sumber yang sama, dalam praktiknya, browser dan CDN tidak menerapkan perilaku ini, dan tidak memungkinkan Anda untuk me-cache permintaan POST.
Sumber:
Diberikan contoh aplikasi JavaScript berikut (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!')
})
Dan diberikan contoh halaman web berikut (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>
Instal NodeJS, Express, dan mulai aplikasi JavaScript. Buka halaman web di browser Anda. Coba beberapa skenario berbeda untuk menguji perilaku browser:
Ini menunjukkan bahwa, meskipun Anda dapat mengatur Cache-Control
dan Content-Location
menanggapi header, tidak ada cara untuk membuat cache browser permintaan HTTP POST.
Perilaku browser tidak dapat dikonfigurasi, tetapi jika Anda bukan browser, Anda tidak harus terikat oleh aturan RFC.
Jika Anda menulis kode aplikasi, tidak ada yang menghentikan Anda untuk secara eksplisit menyimpan permintaan POST (pseudocode):
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, proksi, dan gateway tidak harus mengikuti RFC juga. Misalnya, jika Anda menggunakan Fastly sebagai CDN Anda, Fastly memungkinkan Anda untuk menulis logika VCL khusus untuk men-cache permintaan POST .
Apakah permintaan POST Anda harus di-cache atau tidak tergantung pada konteksnya.
Misalnya, Anda dapat meminta Elasticsearch atau GraphQL menggunakan POST di mana permintaan dasar Anda idempoten. Dalam kasus tersebut, mungkin perlu atau tidak masuk akal untuk men-cache respon tergantung pada use case.
Di API RESTful, permintaan POST biasanya membuat sumber daya dan tidak boleh di-cache. Ini juga merupakan pemahaman RFC tentang POST bahwa itu bukan operasi idempoten.
Jika Anda menggunakan GraphQL dan membutuhkan caching HTTP di seluruh CDN dan browser, pertimbangkan apakah mengirim kueri menggunakan metode GET memenuhi persyaratan Anda alih-alih POST . Sebagai peringatan, browser dan CDN yang berbeda mungkin memiliki batas panjang URI yang berbeda, tetapi operasi daftar aman (daftar putih kueri), sebagai praktik terbaik untuk aplikasi GraphQL yang menghadap ke luar, dapat mempersingkat URI.
Jika itu sesuatu yang tidak benar-benar mengubah data di situs Anda, itu haruslah permintaan GET. Bahkan jika itu adalah formulir, Anda masih dapat mengaturnya sebagai permintaan dapatkan. Sementara, seperti yang ditunjukkan orang lain, Anda bisa men-cache hasil POST, itu tidak masuk akal semantik karena POST menurut definisi mengubah data.
Dengan firefox 27.0 & dengan httpfox, pada 19 Mei 2014, saya melihat satu baris dari ini: 00: 03: 58.777 0.488 657 (393) teks POST (Cache) / html https://users.jackiszhp.info/S4UP
Jelas, respons metode posting di-cache, dan juga di https. Luar biasa!
POST digunakan di stateful Ajax. Mengembalikan respons yang di-cache untuk POST mengalahkan saluran komunikasi dan efek samping dari menerima pesan. Ini Sangat Sangat Buruk. Ini juga menyulitkan untuk dilacak. Sangat direkomendasikan.
Contoh sepele adalah pesan bahwa, sebagai efek samping, membayar gaji Anda $ 10.000 minggu ini. Anda TIDAK ingin mendapatkan "OK, sudah lewat!" halaman belakang yang di-cache minggu lalu. Kasus dunia nyata lainnya yang lebih kompleks menghasilkan keriuhan yang serupa.