Réponses:
La RFC 2616 correspondante dans la section 9.5 (POST) permet la mise en cache de la réponse à un message POST, si vous utilisez les en-têtes appropriés.
Les réponses à cette méthode ne peuvent pas être mises en cache, sauf si la réponse inclut les champs d'en-tête Cache-Control ou Expires appropriés. Cependant, la réponse 303 (Voir autre) peut être utilisée pour demander à l'agent utilisateur de récupérer une ressource pouvant être mise en cache.
Notez que le même RFC indique explicitement dans la section 13 (Caching in HTTP) qu'un cache doit invalider l'entité correspondante après une requête POST .
Certaines méthodes HTTP DOIVENT provoquer l'invalidation d'une entité par un cache. Il s'agit soit de l'entité référencée par Request-URI, soit par les en-têtes Location ou Content-Location (le cas échéant). Ces méthodes sont:
- PUT - DELETE - POST
Je ne vois pas clairement comment ces spécifications peuvent permettre une mise en cache significative.
Cela est également reflété et clarifié dans la RFC 7231 (section 4.3.3.), Qui rend obsolète la RFC 2616.
Les réponses aux demandes POST ne peuvent être mises en cache que lorsqu'elles incluent
des informations de fraîcheur explicites (voir la section 4.2.1 de la [RFC7234]).
Cependant, la mise en cache POST n'est pas largement implémentée. Pour les cas où un serveur d'origine souhaite que le client puisse mettre en cache le résultat d'un POST d'une manière qui puisse être réutilisée par un GET ultérieur, le serveur d'origine PEUT envoyer une réponse 200 (OK) contenant le résultat et un Content-Location champ d'en-tête qui a la même valeur que l'URI de demande effective du POST (paragraphe 3.1.4.2).
Selon cela, le résultat d'un POST mis en cache (si cette capacité est indiquée par le serveur) peut être ultérieurement utilisé comme résultat d'une requête GET pour le même URI.
Selon RFC 2616 Section 9.5:
"Les réponses à la méthode POST ne peuvent pas être mises en cache, À MOINS QUE la réponse n'inclue les champs d'en-tête Cache-Control ou Expires appropriés."
Donc, OUI, vous pouvez mettre en cache la réponse à la requête POST, mais uniquement si elle arrive avec les en-têtes appropriés. Dans la plupart des cas, vous ne souhaitez pas mettre en cache la réponse. Mais dans certains cas - comme si vous n'enregistrez aucune donnée sur le serveur - c'est tout à fait approprié.
Notez cependant que de nombreux navigateurs, y compris Firefox 3.0.10 actuel, ne mettront pas en cache la réponse POST quels que soient les en-têtes. IE se comporte plus intelligemment à cet égard.
Maintenant, je veux clarifier une certaine confusion ici concernant RFC 2616 S. 13.10. La méthode POST sur un URI "n'invalide pas la ressource pour la mise en cache" comme certains l'ont indiqué ici. Il rend obsolète une version précédemment mise en cache de cet URI, même si ses en-têtes de contrôle de cache indiquaient une fraîcheur de plus longue durée.
GET
et POST
. Si vous êtes un cache assis entre le client et le serveur, vous voyez GET /foo
et vous mettez en cache la réponse. Ensuite , vous voyez POST /foo
alors vous devez invalider la réponse en cache de GET /foo
même si la POST
réponse ne comprend pas les en- têtes de contrôle de cache , car ils sont les mêmes URI , donc le prochain GET /foo
aura revalider même si les en- têtes d' origine indiqué le cache serait encore en direct (si vous n'aviez pas vu la POST /foo
demande)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. Quel est donc l'intérêt d'une telle API POST en premier lieu?
Global:
Fondamentalement, POST n'est pas une opération idempotente . Vous ne pouvez donc pas l'utiliser pour la mise en cache. GET doit être une opération idempotente, elle est donc couramment utilisée pour la mise en cache.
Veuillez consulter la section 9.1 du HTTP 1.1 RFC 2616 S. 9.1 .
Autre que la sémantique de la méthode GET:
La méthode POST elle-même est sémantiquement destinée à publier quelque chose sur une ressource. POST ne peut pas être mis en cache car si vous faites quelque chose une fois contre deux fois contre trois fois, vous modifiez la ressource du serveur à chaque fois. Chaque demande compte et doit être envoyée au serveur.
La méthode PUT elle-même est sémantiquement destinée à placer ou créer une ressource. C'est une opération idempotente, mais elle ne sera pas utilisée pour la mise en cache car un DELETE aurait pu se produire entre-temps.
La méthode DELETE elle-même est sémantiquement destinée à supprimer une ressource. C'est une opération idempotente, mais elle ne sera pas utilisée pour la mise en cache car un PUT aurait pu se produire entre-temps.
Concernant la mise en cache côté client:
Un navigateur Web transmettra toujours votre demande même s'il a une réponse d'une opération POST précédente. Par exemple, vous pouvez envoyer des e-mails avec Gmail à quelques jours d'intervalle. Ils peuvent avoir le même sujet et le même corps, mais les deux e-mails doivent être envoyés.
Concernant la mise en cache proxy:
Un serveur HTTP proxy qui transmet votre message au serveur ne mettra jamais en cache autre chose qu'une requête GET ou HEAD.
Concernant la mise en cache du serveur:
Un serveur par défaut ne traiterait pas automatiquement une requête POST en vérifiant son cache. Mais bien sûr, une requête POST peut être envoyée à votre application ou à votre complément et vous pouvez avoir votre propre cache que vous lisez lorsque les paramètres sont les mêmes.
Invalidation d'une ressource:
La vérification de HTTP 1.1 RFC 2616 S. 13.10 montre que la méthode POST doit invalider la ressource pour la mise en cache.
Si vous mettez en cache une réponse POST, elle doit être dirigée vers l'application Web. C'est ce que signifie «Les réponses à cette méthode ne peuvent pas être mises en cache, à moins que la réponse n'inclue les champs d'en-tête Cache-Control ou Expires appropriés».
On peut supposer en toute sécurité que l'application, qui sait si les résultats d'un POST sont idempotents ou non, décide d'attacher ou non les en-têtes de contrôle de cache nécessaires et appropriés. Si des en-têtes suggérant que la mise en cache est autorisée sont présents, l'application vous indique que le POST est, en réalité, un super-GET; que l'utilisation de POST n'était requise qu'en raison de la quantité de données inutiles et non pertinentes (à l'utilisation de l'URI comme clé de cache) nécessaires pour effectuer l'opération idempotente.
Les GET suivants peuvent être servis à partir du cache sous cette hypothèse.
Une application qui ne parvient pas à joindre les en-têtes nécessaires et corrects pour différencier les réponses POST pouvant être mises en cache et non cachable est responsable de tout résultat de mise en cache non valide.
Cela dit, chaque POST qui atteint le cache nécessite une validation à l'aide d'en-têtes conditionnels. Cela est nécessaire pour actualiser le contenu du cache afin d'éviter que les résultats d'un POST ne soient reflétés dans les réponses aux demandes avant l'expiration de la durée de vie de l'objet.
Mark Nottingham a analysé quand il est possible de mettre en cache la réponse d'un POST. Notez que les requêtes suivantes qui souhaitent tirer parti de la mise en cache doivent être des requêtes GET ou HEAD. Voir aussi la sémantique http
Les POST ne traitent pas les représentations d'état identifié, 99 fois sur 100. Cependant, il y a un cas où c'est le cas; lorsque le serveur fait tout son possible pour dire que cette réponse POST est une représentation de son URI, en définissant un en-tête Content-Location qui est le même que l'URI de la requête. Lorsque cela se produit, la réponse POST est comme une réponse GET au même URI; il peut être mis en cache et réutilisé - mais uniquement pour les futures requêtes GET.
Si vous vous demandez si vous pouvez mettre en cache une demande de publication et essayez de rechercher une réponse à cette question, vous ne réussirez probablement pas. Lorsque vous recherchez "demande de publication de cache", le premier résultat est cette question StackOverflow.
Les réponses sont un mélange confus de comment la mise en cache devrait fonctionner, comment la mise en cache fonctionne selon la RFC, comment la mise en cache devrait fonctionner selon la RFC et comment la mise en cache fonctionne dans la pratique. Commençons par la RFC, parcourons une démonstration du fonctionnement réel du navigateur, puis parlons des CDN, de GraphQL et d'autres domaines de préoccupation.
Selon la RFC, les requêtes POST doivent invalider le 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
Ce langage suggère que les requêtes POST ne peuvent pas être mises en cache, mais ce n'est pas vrai (dans ce cas). Le cache n'est invalidé que pour les données précédemment stockées. La RFC (semble) clarifier explicitement que oui, vous pouvez mettre en cache les POST
demandes:
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.
Malgré cette langue, la définition de Cache-Control
ne doit pas mettre en cache les POST
requêtes suivantes sur la même ressource. POST
les demandes doivent être envoyées au serveur:
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.
Comment cela peut-il avoir un sens? Eh bien, vous ne mettez pas en cache la POST
demande, vous mettez en cache la ressource.
Le corps de la réponse POST ne peut être mis en cache que pour les requêtes GET ultérieures adressées à la même ressource. Définissez l'en Location
- Content-Location
tête ou dans la réponse POST pour indiquer quelle ressource le corps représente. Ainsi, le seul moyen techniquement valide de mettre en cache une requête POST, est pour les GET suivants sur la même ressource.
La bonne réponse est à la fois:
Bien que la RFC autorise la mise en cache des demandes vers la même ressource, en pratique, les navigateurs et les CDN n'implémentent pas ce comportement et ne vous permettent pas de mettre en cache les demandes POST.
Sources:
Compte tenu de l'exemple d'application JavaScript suivant (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!')
})
Et étant donné l'exemple de page Web suivant (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>
Installez NodeJS, Express et démarrez l'application JavaScript. Ouvrez la page Web dans votre navigateur. Essayez différents scénarios pour tester le comportement du navigateur:
Cela montre que, même si vous pouvez définir les en Cache-Control
- Content-Location
têtes et de réponse, il n'y a aucun moyen de faire en sorte qu'un navigateur cache une requête HTTP POST.
Le comportement du navigateur n'est pas configurable, mais si vous n'êtes pas un navigateur, vous n'êtes pas nécessairement lié par les règles de la RFC.
Si vous écrivez du code d'application, rien ne vous empêche de mettre explicitement en cache les requêtes 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
}
Les CDN, les proxys et les passerelles ne doivent pas nécessairement suivre la RFC non plus. Par exemple, si vous utilisez Fastly comme CDN, Fastly vous permet d'écrire une logique VCL personnalisée pour mettre en cache les requêtes POST .
La mise en cache ou non de votre requête POST dépend du contexte.
Par exemple, vous pouvez interroger Elasticsearch ou GraphQL à l'aide de POST où votre requête sous-jacente est idempotente. Dans ces cas, il peut être judicieux ou non de mettre en cache la réponse en fonction du cas d'utilisation.
Dans une API RESTful, les requêtes POST créent généralement une ressource et ne doivent pas être mises en cache. C'est aussi la compréhension de la RFC du POST selon laquelle ce n'est pas une opération idempotente.
Si vous utilisez GraphQL et que vous avez besoin de la mise en cache HTTP sur les CDN et les navigateurs, déterminez si l'envoi de requêtes à l'aide de la méthode GET répond à vos exigences au lieu de POST . En guise de mise en garde, différents navigateurs et CDN peuvent avoir des limites de longueur d'URI différentes, mais la safelisting des opérations (liste blanche de requêtes), en tant que meilleure pratique pour les applications GraphQL de production externes, peut raccourcir les URI.
Si c'est quelque chose qui ne change pas réellement les données de votre site, il doit s'agir d'une requête GET. Même s'il s'agit d'un formulaire, vous pouvez toujours le définir comme une demande d'obtention. Bien que, comme d'autres le soulignent, vous puissiez mettre en cache les résultats d'un POST, cela n'aurait pas de sens sémantique car un POST par définition modifie des données.
Avec Firefox 27.0 et avec httpfox, le 19 mai 2014, j'ai vu une ligne de ceci: 00: 03: 58.777 0.488 657 (393) POST (Cache) text / html https://users.jackiszhp.info/S4UP
Clairement, la réponse d'une méthode de publication est mise en cache, et elle est également en https. Incroyable!
POST est utilisé dans Ajax avec état. Le renvoi d'une réponse en cache pour un POST annule le canal de communication et les effets secondaires de la réception d'un message. C'est très, très mauvais. C'est aussi une vraie douleur à retrouver. Fortement recommandé contre.
Un exemple trivial serait un message qui, comme effet secondaire, paie votre salaire 10 000 $ la semaine en cours. Vous ne voulez PAS obtenir le "OK, c'est passé!" page précédente qui a été mise en cache la semaine dernière. D'autres cas concrets plus complexes entraînent une hilarité similaire.