Con una semantica di cache molto semplice: se i parametri sono gli stessi (e l'URL è lo stesso, ovviamente), allora è un successo. È possibile? Consigliato?
Con una semantica di cache molto semplice: se i parametri sono gli stessi (e l'URL è lo stesso, ovviamente), allora è un successo. È possibile? Consigliato?
Risposte:
Il corrispondente RFC 2616 nella sezione 9.5 (POST) consente la memorizzazione nella cache della risposta a un messaggio POST, se si utilizzano le intestazioni appropriate.
Le risposte a questo metodo non sono memorizzabili nella cache, a meno che la risposta non includa i campi di intestazione Controllo cache o Scadenza appropriati. Tuttavia, la risposta 303 (Vedi altro) può essere utilizzata per indirizzare l'agente utente a recuperare una risorsa memorizzabile nella cache.
Si noti che lo stesso RFC afferma esplicitamente nella sezione 13 (Caching in HTTP) che una cache deve invalidare l'entità corrispondente dopo una richiesta POST .
Alcuni metodi HTTP DEVONO far invalidare un'entità a una cache. Questa è l'entità a cui fa riferimento l'URI di richiesta o le intestazioni Location o Content-Location (se presenti). Questi metodi sono:
- PUT - DELETE - POST
Non mi è chiaro come queste specifiche possano consentire una memorizzazione nella cache significativa.
Ciò si riflette e chiarisce ulteriormente in RFC 7231 (Sezione 4.3.3.), Che oscura RFC 2616.
Le risposte alle richieste POST sono memorizzabili nella cache solo quando includono
informazioni esplicite sull'aggiornamento (vedere la Sezione 4.2.1 di [RFC7234]).
Tuttavia, la memorizzazione nella cache POST non è ampiamente implementata. Per i casi in cui un server di origine desidera che il client sia in grado di memorizzare nella cache il risultato di un POST in modo che possa essere riutilizzato da un GET successivo, il server di origine PUO 'inviare una risposta 200 (OK) contenente il risultato e una posizione del contenuto campo di intestazione con lo stesso valore dell'URI di richiesta effettiva del POST (Sezione 3.1.4.2).
In base a ciò, il risultato di un POST memorizzato nella cache (se questa capacità è indicata dal server) può essere successivamente utilizzato come risultato di una richiesta GET per lo stesso URI.
Secondo RFC 2616 Sezione 9.5:
"Le risposte al metodo POST non sono memorizzabili nella cache, A MENO CHE la risposta non includa i campi di intestazione Controllo cache o Scadenza appropriati."
Quindi, SÌ, è possibile memorizzare nella cache la risposta alla richiesta POST, ma solo se arriva con le intestazioni appropriate. Nella maggior parte dei casi non si desidera memorizzare nella cache la risposta. Ma in alcuni casi, ad esempio se non si stanno salvando dati sul server, è del tutto appropriato.
Nota, tuttavia molti browser, incluso l'attuale Firefox 3.0.10, non memorizzeranno nella cache la risposta POST indipendentemente dalle intestazioni. IE si comporta in modo più intelligente in questo senso.
Ora, voglio chiarire un po 'di confusione qui riguardo a RFC 2616 S. 13.10. Il metodo POST su un URI non "invalida la risorsa per la memorizzazione nella cache", come alcuni hanno affermato qui. Rende obsoleta una versione precedentemente memorizzata nella cache di tale URI, anche se le intestazioni del controllo cache indicano freschezza di durata maggiore.
GET
e POST
richieste. Se si trova una cache tra il client e il server, si vede GET /foo
e si memorizza nella cache la risposta. Successivamente vedrai che POST /foo
ti verrà richiesto di invalidare la risposta memorizzata nella cache GET /foo
anche se la POST
risposta non include intestazioni di controllo della cache perché sono lo stesso URI , quindi la successiva GET /foo
dovrà riconvalidare anche se le intestazioni originali indicavano che la cache sarebbe comunque live (se non avessi visto la POST /foo
richiesta)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. A che serve allora un'API POST?
Complessivamente:
Fondamentalmente POST non è un'operazione idempotente . Quindi non puoi usarlo per la memorizzazione nella cache. GET dovrebbe essere un'operazione idempotente, quindi viene comunemente utilizzata per la memorizzazione nella cache.
Vedere la sezione 9.1 di HTTP 1.1 RFC 2616 S. 9.1 .
Oltre alla semantica del metodo GET:
Il metodo POST stesso è semanticamente pensato per pubblicare qualcosa su una risorsa. Il POST non può essere memorizzato nella cache perché se si fa qualcosa una volta contro due volte contro tre volte, si modifica ogni volta la risorsa del server. Ogni richiesta è importante e deve essere consegnata al server.
Lo stesso metodo PUT è semanticamente pensato per inserire o creare una risorsa. È un'operazione idempotente, ma non verrà utilizzata per la memorizzazione nella cache perché nel frattempo potrebbe essersi verificato un DELETE.
Il metodo DELETE stesso è semanticamente pensato per eliminare una risorsa. È un'operazione idempotente, ma non verrà utilizzata per la memorizzazione nella cache perché nel frattempo potrebbe essersi verificato un PUT.
Per quanto riguarda la memorizzazione nella cache lato client:
Un browser Web inoltrerà sempre la tua richiesta anche se ha una risposta da una precedente operazione POST. Ad esempio, puoi inviare e-mail con Gmail a distanza di un paio di giorni. Possono essere lo stesso soggetto e lo stesso corpo, ma entrambe le e-mail devono essere inviate.
Per quanto riguarda la memorizzazione nella cache del proxy:
Un server HTTP proxy che inoltra il tuo messaggio al server non memorizzerà mai nella cache nient'altro che una richiesta GET o HEAD.
Per quanto riguarda la memorizzazione nella cache del server:
Un server per impostazione predefinita non gestirà automaticamente una richiesta POST controllando la sua cache. Ma ovviamente una richiesta POST può essere inviata alla tua applicazione o componente aggiuntivo e puoi avere la tua cache da cui leggi quando i parametri sono gli stessi.
Invalidare una risorsa:
Il controllo di HTTP 1.1 RFC 2616 S. 13.10 mostra che il metodo POST dovrebbe invalidare la risorsa per la memorizzazione nella cache.
Se si memorizza nella cache una risposta POST, deve essere nella direzione dell'applicazione Web. Questo è ciò che si intende per "Le risposte a questo metodo non sono memorizzabili, a meno che la risposta includa appropriati campi di intestazione Cache-Control o Expires".
Si può tranquillamente presumere che l'applicazione, che sa se i risultati di un POST sono o meno idempotenti, decide se collegare o meno le intestazioni di controllo della cache necessarie e appropriate. Se sono presenti intestazioni che suggeriscono la memorizzazione nella cache, l'applicazione ti sta dicendo che il POST è, in realtà, un super-GET; che l'uso di POST era richiesto solo a causa della quantità di dati non necessari e irrilevanti (per l'uso dell'URI come chiave di cache) necessari per eseguire l'operazione idempotente.
I seguenti GET possono essere forniti dalla cache in base a questo presupposto.
Un'applicazione che non riesce a collegare le intestazioni necessarie e corrette per distinguere tra risposte POST memorizzabili e non memorizzabili è responsabile di eventuali risultati di memorizzazione nella cache non validi.
Detto questo, ogni POST che colpisce la cache richiede la convalida usando le intestazioni condizionali. Ciò è necessario al fine di aggiornare il contenuto della cache per evitare che i risultati di un POST non si riflettano nelle risposte alle richieste fino a quando non scade la durata dell'oggetto.
Mark Nottingham ha analizzato quando è possibile memorizzare nella cache la risposta di un POST. Si noti che le richieste successive che desiderano sfruttare la memorizzazione nella cache devono essere richieste GET o HEAD. Vedi anche semantica http
I POST non trattano rappresentazioni dello stato identificato, 99 volte su 100. Tuttavia, c'è un caso in cui lo fa; quando il server fa di tutto per dire che questa risposta POST è una rappresentazione del suo URI, impostando un'intestazione Content-Location uguale all'URI della richiesta. Quando ciò accade, la risposta POST è proprio come una risposta GET allo stesso URI; può essere memorizzato nella cache e riutilizzato, ma solo per future richieste GET.
Se ti stai chiedendo se puoi memorizzare nella cache una richiesta di post e provare a cercare una risposta a quella domanda, probabilmente non ci riuscirai. Quando si cerca "richiesta post cache" il primo risultato è questa domanda StackOverflow.
Le risposte sono una miscela confusa di come dovrebbe funzionare la memorizzazione nella cache, come la cache funziona secondo la RFC, come la cache dovrebbe funzionare secondo la RFC e come funziona la cache nella pratica. Cominciamo con RFC, illustriamo come funziona effettivamente il browser, quindi parliamo di CDN, GraphQL e altre aree di interesse.
Per RFC, le richieste POST devono invalidare la 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
Questo linguaggio suggerisce che le richieste POST non sono memorizzabili nella cache, ma ciò non è vero (in questo caso). La cache è invalidata solo per i dati memorizzati in precedenza. L'RFC (sembra) chiarisce esplicitamente che sì, è possibile memorizzare nella cache le POST
richieste:
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.
Nonostante questa lingua, l'impostazione Cache-Control
non deve memorizzare nella cache le POST
richieste successive sulla stessa risorsa. POST
le richieste devono essere inviate al 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.
Che senso ha? Bene, non stai memorizzando nella cachePOST
richiesta, stai memorizzando nella cache la risorsa.
Il corpo della risposta POST può essere memorizzato nella cache solo per successive richieste GET alla stessa risorsa. Impostare il Location
oContent-Location
intestazione nella risposta POST per comunicare quale risorsa rappresenta il corpo. Quindi l'unico modo tecnicamente valido per memorizzare nella cache una richiesta POST, è per GET successivi alla stessa risorsa.
La risposta corretta è entrambe:
Sebbene RFC consenta la memorizzazione nella cache delle richieste alla stessa risorsa, in pratica i browser e i CDN non implementano questo comportamento e non consentono di memorizzare nella cache le richieste POST.
fonti:
Data la seguente applicazione JavaScript di esempio (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!')
})
E data la seguente pagina Web di esempio (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>
Installa NodeJS, Express e avvia l'applicazione JavaScript. Apri la pagina web nel tuo browser. Prova alcuni scenari diversi per testare il comportamento del browser:
Ciò dimostra che, sebbene sia possibile impostare le intestazioni Cache-Control
e la Content-Location
risposta, non è possibile rendere una cache HTTP del browser una richiesta POST.
Il comportamento del browser non è configurabile, ma se non si è un browser, non si è necessariamente vincolati dalle regole della RFC.
Se stai scrivendo il codice dell'applicazione, non c'è nulla che ti impedisca di memorizzare esplicitamente le richieste POST (pseudocodice):
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
}
Neanche CDN, proxy e gateway devono necessariamente seguire la RFC. Ad esempio, se si utilizza Fastly come CDN, Fastly consente di scrivere logiche VCL personalizzate per memorizzare nella cache le richieste POST .
Se la tua richiesta POST deve essere memorizzata nella cache o meno dipende dal contesto.
Ad esempio, è possibile eseguire una query su Elasticsearch o GraphQL utilizzando POST in cui la query sottostante è idempotente. In questi casi, può o non ha senso memorizzare nella cache la risposta in base al caso d'uso.
In un'API RESTful, le richieste POST di solito creano una risorsa e non devono essere memorizzate nella cache. Questa è anche la comprensione da parte della RFC del POST che non si tratta di un'operazione idempotente.
Se stai usando GraphQL e richiedi la memorizzazione nella cache HTTP su CDN e browser, valuta se l'invio di query utilizzando il metodo GET soddisfa i tuoi requisiti anziché POST . Come avvertimento, browser e CDN diversi possono avere limiti di lunghezza URI diversi, ma la lista di sicurezza delle operazioni (whitelist di query), come best practice per le app GraphQL di produzione rivolte verso l'esterno, può abbreviare gli URI.
Se è qualcosa che in realtà non modifica i dati sul tuo sito, dovrebbe essere una richiesta GET. Anche se si tratta di un modulo, è comunque possibile impostarlo come richiesta get. Mentre, come altri sottolineano, è possibile memorizzare nella cache i risultati di un POST, non avrebbe senso semantico perché un POST per definizione sta cambiando i dati.
Con firefox 27.0 e httpfox, il 19 maggio 2014, ho visto una riga di questo: 00: 03: 58.777 0.488 657 (393) POST (Cache) text / html https://users.jackiszhp.info/S4UP
Chiaramente, la risposta di un metodo post è memorizzata nella cache ed è anche in https. Incredibile!
Il POST viene utilizzato in Ajax con stato. Restituire una risposta memorizzata nella cache per un POST sconfigge il canale di comunicazione e gli effetti collaterali della ricezione di un messaggio. Questo è molto, molto male. È anche un vero dolore da rintracciare. Altamente raccomandato contro.
Un esempio banale sarebbe un messaggio che, come effetto collaterale, paga il tuo stipendio $ 10.000 la settimana in corso. NON vuoi ottenere "OK, è passato!" pagina indietro che è stata memorizzata nella cache la settimana scorsa. Altri casi più complessi del mondo reale si traducono in una simile ilarità.