Respostas:
O RFC 2616 correspondente na seção 9.5 (POST) permite o armazenamento em cache da resposta a uma mensagem POST, se você usar os cabeçalhos apropriados.
As respostas a esse método não podem ser armazenadas em cache, a menos que a resposta inclua os campos de cabeçalho Cache-Control ou Expir apropriados. No entanto, a resposta 303 (Consulte Outro) pode ser usada para direcionar o agente do usuário para recuperar um recurso armazenável em cache.
Observe que a mesma RFC afirma explicitamente na seção 13 (Armazenamento em cache em HTTP) que um cache deve invalidar a entidade correspondente após uma solicitação POST .
Alguns métodos HTTP DEVEM causar um cache para invalidar uma entidade. Essa é a entidade mencionada pelo Request-URI ou pelos cabeçalhos Location ou Content-Location (se presentes). Esses métodos são:
- PUT - DELETE - POST
Não está claro para mim como essas especificações podem permitir um cache significativo.
Isso também é refletido e esclarecido na RFC 7231 (Seção 4.3.3.), Que obsoleta a RFC 2616.
As respostas às solicitações POST só podem ser armazenadas em cache quando incluem
informações explícitas de atualização (consulte a Seção 4.2.1 de [RFC7234]).
No entanto, o armazenamento em cache do POST não é amplamente implementado. Para casos em que um servidor de origem deseja que o cliente possa armazenar em cache o resultado de um POST de uma maneira que possa ser reutilizada por um GET posterior, o servidor de origem PODE enviar uma resposta 200 (OK) contendo o resultado e um Local de Conteúdo campo de cabeçalho que possui o mesmo valor que o URI de solicitação efetiva do POST (Seção 3.1.4.2).
De acordo com isso, o resultado de um POST em cache (se essa capacidade é indicada pelo servidor) pode ser usado posteriormente como resultado de uma solicitação GET para o mesmo URI.
De acordo com a Seção 9.5 da RFC 2616:
"As respostas ao método POST não são armazenáveis em cache, a menos que a resposta inclua campos de cabeçalho de Controle de Cache ou Expira apropriados"
Portanto, SIM, você pode armazenar em cache a resposta da solicitação POST, mas apenas se ela chegar com os cabeçalhos apropriados. Na maioria dos casos, você não deseja armazenar em cache a resposta. Mas em alguns casos - como se você não estiver salvando nenhum dado no servidor - é totalmente apropriado.
Observe que, no entanto, muitos navegadores, incluindo o Firefox 3.0.10 atual, não armazenam em cache a resposta do POST, independentemente dos cabeçalhos. O IE se comporta de maneira mais inteligente a esse respeito.
Agora, quero esclarecer algumas confusões aqui sobre a RFC 2616 S. 13.10. O método POST em um URI não "invalida o recurso para armazenamento em cache", como alguns declararam aqui. Ele torna uma versão em cache anterior desse URI obsoleta, mesmo se seus cabeçalhos de controle de cache indicassem atualização de maior duração.
GET
e POST
solicitações. Se você é um cache entre o cliente e o servidor, vê GET /foo
e armazena em cache a resposta. Em seguida, você vê POST /foo
que é necessário invalidar a resposta em cache, GET /foo
mesmo que a POST
resposta não inclua nenhum cabeçalho de controle de cache porque eles são o mesmo URI , portanto, o próximo GET /foo
terá que revalidar, mesmo que os cabeçalhos originais indicassem que o cache ainda estaria. ao vivo (se você não tinha visto a POST /foo
pedido)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. Qual é o sentido de uma API POST em primeiro lugar?
No geral:
Basicamente, o POST não é uma operação idempotente . Portanto, você não pode usá-lo para armazenar em cache. GET deve ser uma operação idempotente, por isso é comumente usada para armazenamento em cache.
Consulte a seção 9.1 do HTTP 1.1 RFC 2616 S. 9.1 .
Diferente da semântica do método GET:
O próprio método POST é destinado semanticamente a publicar algo em um recurso. O POST não pode ser armazenado em cache porque se você fizer algo uma vez ou duas vezes e três vezes, estará alterando o recurso do servidor a cada vez. Cada solicitação é importante e deve ser entregue ao servidor.
O próprio método PUT destina-se semanticamente a colocar ou criar um recurso. É uma operação idempotente, mas não será usada para armazenar em cache porque um DELETE pode ter ocorrido nesse meio tempo.
O próprio método DELETE destina-se semanticamente a excluir um recurso. É uma operação idempotente, mas não será usada para armazenar em cache, porque uma PUT pode ter ocorrido nesse meio tempo.
Em relação ao cache do lado do cliente:
Um navegador da Web sempre encaminhará sua solicitação, mesmo que tenha uma resposta de uma operação anterior do POST. Por exemplo, você pode enviar e-mails com o gmail com alguns dias de diferença. Eles podem ser o mesmo assunto e corpo, mas os dois e-mails devem ser enviados.
Em relação ao cache do proxy:
Um servidor HTTP proxy que encaminha sua mensagem para o servidor nunca armazenaria em cache nada além de uma solicitação GET ou HEAD.
Em relação ao cache do servidor:
Um servidor por padrão não processa automaticamente uma solicitação POST, verificando seu cache. Mas é claro que uma solicitação POST pode ser enviada para o seu aplicativo ou suplemento e você pode ter seu próprio cache do qual lê quando os parâmetros são os mesmos.
Invalidando um recurso:
A verificação do HTTP 1.1 RFC 2616 S. 13.10 mostra que o método POST deve invalidar o recurso para armazenamento em cache.
Se você armazenar em cache uma resposta POST, ela deverá estar na direção do aplicativo da web. É isso que significa "As respostas a esse método não podem ser alteradas, a menos que a resposta inclua os campos apropriados de cabeçalho Control-Cache ou Expires".
Pode-se supor com segurança que o aplicativo, que sabe se os resultados de um POST são idempotentes, decide se deve ou não anexar os cabeçalhos de controle de cache necessários e adequados. Se os cabeçalhos que sugerem que o cache é permitido estão presentes, o aplicativo informa que o POST é, na realidade, um super GET; que o uso do POST era necessário apenas devido à quantidade de dados desnecessários e irrelevantes (para o uso do URI como chave de cache) necessários para executar a operação idempotente.
Os GETs a seguir podem ser veiculados no cache sob essa suposição.
Um aplicativo que falha ao anexar os cabeçalhos necessários e corretos para diferenciar entre respostas POST cachable e não cachable é responsável por quaisquer resultados de armazenamento em cache inválidos.
Dito isto, cada POST que atinge o cache requer validação usando cabeçalhos condicionais. Isso é necessário para atualizar o conteúdo do cache para evitar que os resultados de um POST não sejam refletidos nas respostas às solicitações até que a vida útil do objeto expire.
Mark Nottingham analisou quando é possível armazenar em cache a resposta de um POST. Observe que os pedidos subsequentes que desejam tirar proveito do armazenamento em cache devem ser pedidos GET ou HEAD. Veja também semântica http
Os POSTs não lidam com representações do estado identificado, 99 vezes em 100. No entanto, há um caso em que ocorre; quando o servidor faz o possível para dizer que essa resposta POST é uma representação de seu URI, configurando um cabeçalho de local do conteúdo igual ao URI da solicitação. Quando isso acontece, a resposta POST é como uma resposta GET para o mesmo URI; pode ser armazenado em cache e reutilizado - mas apenas para solicitações GET futuras.
Se você está se perguntando se pode armazenar em cache uma solicitação de postagem e tenta pesquisar uma resposta para essa pergunta, provavelmente não terá êxito. Ao pesquisar "solicitação de postagem de cache", o primeiro resultado é essa pergunta do StackOverflow.
As respostas são uma mistura confusa de como o cache deve funcionar, como o cache funciona de acordo com o RFC, como o cache deve funcionar de acordo com o RFC e como o cache funciona na prática. Vamos começar com o RFC, mostrar uma demonstração de como o navegador realmente funciona e depois falar sobre CDNs, GraphQL e outras áreas de preocupação.
De acordo com o RFC, os pedidos POST devem invalidar o 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
Esse idioma sugere que as solicitações POST não podem ser armazenadas em cache, mas isso não é verdade (neste caso). O cache é invalidado apenas para dados armazenados anteriormente. O RFC (parece) esclarece explicitamente que sim, você pode armazenar em cache POST
solicitações:
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.
Apesar desse idioma, a configuração de Cache-Control
não deve armazenar em cache POST
solicitações subsequentes no mesmo recurso. POST
solicitações devem ser enviadas ao servidor:
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.
Como isso faz sentido? Bem, você não está armazenando em cache a POST
solicitação, está armazenando em cache o recurso.
O corpo da resposta POST pode ser armazenado em cache apenas para solicitações GET subsequentes para o mesmo recurso. Defina o Location
ouContent-Location
cabeçalho na resposta POST para comunicar qual recurso o corpo representa. Portanto, a única maneira tecnicamente válida de armazenar em cache uma solicitação POST é para GETs subsequentes no mesmo recurso.
A resposta correta é ambas:
Embora o RFC permita solicitações de cache para o mesmo recurso, na prática, navegadores e CDNs não implementam esse comportamento e não permitem o cache de solicitações POST.
Fontes:
Dado o seguinte exemplo de aplicativo 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!')
})
E dado o seguinte exemplo de página da web (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>
Instale o NodeJS, Express e inicie o aplicativo JavaScript. Abra a página da web no seu navegador. Experimente alguns cenários diferentes para testar o comportamento do navegador:
Isso mostra que, embora você possa definir os cabeçalhos Cache-Control
e Content-Location
resposta, não há como tornar um navegador em cache uma solicitação HTTP POST.
O comportamento do navegador não é configurável, mas se você não é um navegador, não está necessariamente vinculado às regras da RFC.
Se você estiver escrevendo o código do aplicativo, não há nada que impeça o armazenamento em cache de solicitações POST explicitamente (pseudocódigo):
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
}
CDNs, proxies e gateways também não precisam necessariamente seguir o RFC. Por exemplo, se você usar o Fastly como CDN, o Fastly permitirá que você escreva lógica VCL personalizada para armazenar em cache solicitações POST .
Se sua solicitação POST deve ser armazenada em cache ou não, depende do contexto.
Por exemplo, você pode consultar o Elasticsearch ou o GraphQL usando POST, onde sua consulta subjacente é idempotente. Nesses casos, pode ou não fazer sentido armazenar em cache a resposta, dependendo do caso de uso.
Em uma API RESTful, as solicitações POST geralmente criam um recurso e não devem ser armazenadas em cache. Este também é o entendimento da RFC do POST de que não é uma operação idempotente.
Se você estiver usando o GraphQL e precisar de cache HTTP entre CDNs e navegadores, considere se o envio de consultas usando o método GET atende aos seus requisitos em vez do POST . Como uma ressalva, navegadores e CDNs diferentes podem ter limites de comprimento de URI diferentes, mas a lista segura de operações (lista de permissões), como uma prática recomendada para aplicativos GraphQL de produção voltados para o exterior, pode reduzir os URIs.
Se algo que realmente não altera os dados do seu site, deve ser uma solicitação GET. Mesmo que seja um formulário, você ainda pode defini-lo como uma solicitação de obtenção. Enquanto, como outros apontam, você pode armazenar em cache os resultados de um POST, isso não faria sentido semântico porque, por definição, um POST está alterando os dados.
Com o firefox 27.0 e com o httpfox, em 19 de maio de 2014, vi uma linha disso: 00: 03: 58.777 0.488 657 (393) POST (Cache) text / html https://users.jackiszhp.info/S4UP
Claramente, a resposta de um método de postagem é armazenada em cache e também está em https. Inacreditável!
POST é usado no Ajax com monitoração de estado. Retornar uma resposta em cache para um POST anula o canal de comunicação e os efeitos colaterais de receber uma mensagem. Isso é muito, muito ruim. Também é uma dor real rastrear. Altamente recomendado contra.
Um exemplo trivial seria uma mensagem que, como efeito colateral, paga ao seu salário US $ 10.000 na semana atual. Você NÃO deseja obter o "OK, passou!" página de volta que foi armazenada em cache na semana passada. Outros casos reais mais complexos resultam em hilaridade semelhante.