使用非常简单的缓存机制:如果参数相同(当然,URL也相同),则命中。这是否可行?建议采用?
在第9.5节(POST)中,对应的RFC 2616允许缓存POST消息的响应,如果您使用适当的标头。
除非响应包含适当的Cache-Control或Expires标头字段,否则不得缓存此方法的响应。但是,可以使用303(See Other)响应将用户代理重定向到可缓存的资源。
请注意,同一RFC在第13节(HTTP缓存)中明确指出,在POST请求之后,缓存必须使相应的实体失效。
某些HTTP方法必须导致缓存使实体失效。这既可以是由Request-URI引用的实体,也可以是由Location或Content-Location标头引用的实体(如果存在)。这些方法是:
- PUT - DELETE - POST
我不清楚这些规范如何允许有意义的缓存。
这也在RFC 7231(第4.3.3节)中有所体现和进一步澄清,该标准废除了RFC 2616。
仅当POST响应包括明确的新鲜度信息时(请参阅[RFC7234]的第4.2.1节),才可以缓存响应。然而,POST缓存并不常用。 对于源服务器希望客户端能够缓存POST结果以便稍后重用的情况,源服务器可以发送一个包含结果和Content-Location头字段的200(OK)响应,该头字段具有与POST的有效请求URI(第3.1.4.2节)相同的值。
根据此规范,如果服务器指示了此功能,缓存的POST结果可以随后用作同一URI的GET请求的结果。
所以,是的,您可以缓存POST请求的响应,但仅当它带有适当的头信息时才能这样做。在大多数情况下,您不想缓存响应。但在某些情况下 - 比如如果您没有在服务器上保存任何数据 - 这是完全合适的。“POST方法的响应是不可缓存的,除非响应包括适当的Cache-Control或Expires头字段。”
GET
和POST
请求中使用相同的URI,那么"使缓存版本过期"就适用。如果您是客户端和服务器之间的缓存,则会看到GET /foo
并将其缓存下来。接下来,您会看到POST /foo
,即使POST
响应不包括任何缓存控制头,因为它们是相同的URI,因此您必须使从GET /foo
获取的缓存响应失效,这样下一个GET /foo
请求就必须重新验证,即使原始头部指示缓存仍然有效(如果您没有看到POST /foo
请求)。 - Stephen Connolly13.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请求。在POST响应中设置Location
或Content-Location
头来指示响应体表示的资源。所以,唯一有效的缓存POST请求的方式是用于后续对同一资源的GET请求。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>
Cache-Control
和Content-Location
响应头,也没有办法使浏览器缓存HTTP 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
}
总体而言:
基本上,POST不是幂等操作,因此不能用于缓存。GET应该是一个幂等操作,所以通常用于缓存。
请参阅HTTP 1.1 RFC 2616 S.9.1第9.1节。
除GET方法的语义外:
POST方法本身的语义是将某些内容发布到资源中。POST不能被缓存,因为如果您做一次、两次或三次操作,则每次都会改变服务器的资源。每个请求都很重要,都应该发送到服务器。
PUT方法本身的语义是放置或创建资源。它是一个幂等操作,但不会用于缓存,因为在此期间可能发生了DELETE操作。
DELETE方法本身的语义是删除资源。它是一个幂等操作,但不会用于缓存,因为在此期间可能发生了PUT操作。
关于客户端缓存:
Web浏览器将始终转发您的请求,即使它具有来自先前POST操作的响应。例如,您可以隔几天使用gmail发送相同主题和正文的电子邮件。每封电子邮件都应该发出。
关于代理缓存:
将您的消息转发到服务器的代理HTTP服务器永远不会缓存除GET或HEAD请求以外的任何内容。
关于服务器缓存:
默认情况下,服务器不会通过检查其缓存来自动处理POST请求。但是,当参数相同时,可以将POST请求发送到您的应用程序或插件,并从缓存中读取。
使资源无效:
查看HTTP 1.1 RFC 2616 S. 13.10可知,POST方法应使缓存失效。
99次中,POST不涉及已识别状态的表示。 然而,有一种情况例外;当服务器特别声明此POST响应是其URI的表示形式时, 通过设置Content-Location标题与请求URI相同。当发生这种情况时, POST响应就像对同一URI的GET响应一样;它可以被缓存和重复使用--但仅限于将来的GET请求。
使用Firefox 27.0和HttpFox,在2014年5月19日,我看到了这样一行代码:
00:03:58.777 0.488 657 (393) POST (Cache) text/html https://users.jackiszhp.info/S4UP
显然,POST方法的响应被缓存,并且是在HTTPS中。真不可思议!
POST 在有状态的 Ajax 中使用。返回 POST 的缓存响应会破坏通信渠道和接收消息的副作用。这是非常非常糟糕的。而且,要追踪它也是真正的痛苦。强烈建议不要这样做。
一个微不足道的例子是一条消息,其副作用是支付你本周的 10,000 美元工资。你不想得到上周缓存的“好的,它通过了!”页面。其他更复杂的实际情况会导致类似的滑稽结果。