是否可以在 HTTP 中缓存 POST 方法?
使用非常简单的缓存语义:如果参数相同(当然,URL 也相同),那么它就会成功。 那可能吗? 受到推崇的?
With very simple caching semantics: if the parameters are the same (and the URL is the same, of course), then it's a hit. Is that possible? Recommended?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
第 9.5 节(POST)中相应的 RFC 2616 允许缓存响应 到 POST 消息(如果您使用适当的标头)。
请注意,同一 RFC 在第 13 节(HTTP 中的缓存)中明确指出,缓存必须在 POST 请求之后使相应的实体无效。
我不清楚这些规范如何允许有意义的缓存。
RFC 7231(第 4.3.3 节)也反映并进一步阐明了这一点,其中已废弃 RFC 2616。
据此,缓存的 POST 的结果(如果服务器指示了此能力)可以随后用作同一 URI 的 GET 请求的结果。
The corresponding RFC 2616 in section 9.5 (POST) allows the caching of the response to a POST message, if you use the appropriate headers.
Note that the same RFC states explicitly in section 13 (Caching in HTTP) that a cache must invalidate the corresponding entity after a POST request.
It's not clear to me how these specifications can allow meaningful caching.
This is also reflected and further clarified in RFC 7231 (Section 4.3.3.), which obsoletes RFC 2616.
According to this, the result of a cached POST (if this ability is indicated by the server) can be subsequently used for as the result of a GET request for the same URI.
根据 RFC 2616 第 9.5 节:
所以,是的,您可以缓存 POST 请求响应,但前提是它带有适当的标头。在大多数情况下,您不想缓存响应。但在某些情况下 - 例如,如果您没有保存任何响应服务器上的数据 - 这是完全合适的,
但是许多浏览器,包括当前的 Firefox 3.0.10,不会缓存 POST 响应,无论 IE 在这方面表现得更加聪明
。关于 URI 上的 RFC 2616 S.13.10,它不会“使缓存资源无效”,即使其缓存控制标头指示较长持续时间的新鲜度,它也会使该 URI 的先前缓存版本过时。 。
According to RFC 2616 Section 9.5:
So, YES, you can cache POST request response but only if it arrives with appropriate headers. In most cases you don't want to cache the response. But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
Note, however many browsers, including current Firefox 3.0.10, will not cache POST response regardless of the headers. IE behaves more smartly in this respect.
Now, i want to clear up some confusion here regarding RFC 2616 S. 13.10. POST method on a URI doesn't "invalidate the resource for caching" as some have stated here. It makes a previously cached version of that URI stale, even if its cache control headers indicated freshness of longer duration.
如果您想知道是否可以缓存发布请求,并尝试研究该问题的答案,您可能不会成功。 当搜索“缓存发布请求”时,第一个结果是这个 StackOverflow 问题。
答案是一个混乱的混合体,包括缓存应该如何工作、缓存如何根据 RFC 工作、缓存应该如何根据 RFC 工作以及缓存在实践中如何工作。 让我们从 RFC 开始,了解浏览器的实际工作原理,然后讨论 CDN、GraphQL 和其他值得关注的领域。
RFC 2616
根据 RFC,POST 请求必须使缓存无效:
该语言表明 POST 请求不可缓存,但事实并非如此(在本例中)。 缓存仅对以前存储的数据无效。 RFC(似乎)明确澄清,是的,您可以缓存
POST
请求:尽管使用这种语言,但设置
Cache-Control
不得缓存后续POST 请求相同的资源。
POST
请求必须发送到服务器:这有什么意义? 好吧,您不是在缓存
POST
请求,而是在缓存资源。只能缓存对同一资源的后续 GET 请求的 POST 响应正文。 在 POST 响应中设置
Location
或Content-Location
标头以传达正文代表的资源。 因此,缓存 POST 请求的唯一技术上有效的方法是针对同一资源的后续 GET。正确答案都是:
实际上,浏览器和 CDN 不会实现此行为,并且不允许您缓存 POST 请求。
资料来源:
浏览器行为演示
给定以下示例 JavaScript 应用程序 (index.js):
并给定以下示例网页 (index.html):
安装 NodeJS、Express 并启动JavaScript 应用程序。 在浏览器中打开网页。 尝试几种不同的场景来测试浏览器行为:
这表明,即使您可以设置
Cache-Control
和Content-Location
响应标头,也无法使浏览器缓存 HTTP POST 请求。我必须遵循 RFC 吗?
浏览器行为不可配置,但如果您不是浏览器,则不一定受 RFC 规则的约束。
如果您正在编写应用程序代码,则没有什么可以阻止您显式缓存 POST 请求(伪代码):
CDN、代理和网关也不一定必须遵循 RFC。 例如,如果您使用 Fastly 作为 CDN,Fastly 允许您编写 自定义 VCL< /a> 缓存 POST 请求的逻辑。
我应该缓存 POST 请求吗?
是否应缓存您的 POST 请求取决于上下文。
例如,您可以使用 POST 查询 Elasticsearch 或 GraphQL,其中您的底层查询是幂等的。 在这些情况下,根据用例缓存响应可能有意义,也可能没有意义。
在 RESTful API 中,POST 请求通常会创建资源并且不应缓存。 这也是RFC对POST的理解,认为它不是幂等操作。
GraphQL
如果您使用 GraphQL 并且需要跨 CDN 和浏览器进行 HTTP 缓存,请考虑是否使用 GET 方法 满足您的要求,而不是 POST。 需要注意的是,不同的浏览器和 CDN 可能有不同的 URI 长度限制,但操作安全列表(查询白名单)作为面向外部的生产 GraphQL 应用程序的最佳实践,可以缩短 URI。
If you're wondering whether you can cache a post request, and try researching an answer to that question, you likely won't succeed. When searching "cache post request" the first result is this StackOverflow question.
The answers are a confused mixture of how caching should work, how caching works according to the RFC, how caching should work according to the RFC, and how caching works in practice. Let's start with the RFC, walk through how browser's actually work, then talk about CDNs, GraphQL, and other areas of concern.
RFC 2616
Per the RFC, POST requests must invalidate the cache:
This language suggests POST requests are not cacheable, but that is not true (in this case). The cache is only invalidated for previously stored data. The RFC (appears to) explicitly clarify that yes, you can cache
POST
requests:Despite this language, setting the
Cache-Control
must not cache subsequentPOST
requests to the same resource.POST
requests must be sent to the server:How does that make sense? Well, you're not caching the
POST
request, you're caching the resource.The POST response body can only be cached for subsequent GET requests to the same resource. Set the
Location
orContent-Location
header in the POST response to communicate which resource the body represents. So the only technically valid way to cache a POST request, is for subsequent GETs to the same resource.The correct answer is both:
Although the RFC allows for caching requests to the same resource, in practice, browsers and CDNs do not implement this behavior, and do not allow you to cache POST requests.
Sources:
Demonstration of Browser Behavior
Given the following example JavaScript application (index.js):
And given the following example web page (index.html):
Install NodeJS, Express, and start the JavaScript application. Open the web page in your browser. Try a few different scenarios to test browser behavior:
This shows that, even though you can set the
Cache-Control
andContent-Location
response headers, there is no way to make a browser cache an HTTP POST request.Do I have to follow the RFC?
Browser behavior is not configurable, but if you're not a browser, you aren't necessarily bound by the rules of the RFC.
If you're writing application code, there's nothing stopping you from explicitly caching POST requests (pseudocode):
CDNs, proxies, and gateways do not necessarily have to follow the RFC either. For example, if you use Fastly as your CDN, Fastly allows you to write custom VCL logic to cache POST requests.
Should I cache POST requests?
Whether your POST request should be cached or not depends on the context.
For example, you might query Elasticsearch or GraphQL using POST where your underlying query is idempotent. In those cases, it may or may not make sense to cache the response depending on the use case.
In a RESTful API, POST requests usually create a resource and should not be cached. This is also the RFC's understanding of POST that it is not an idempotent operation.
GraphQL
If you're using GraphQL and require HTTP caching across CDNs and browsers, consider whether sending queries using the GET method meets your requirements instead of POST. As a caveat, different browsers and CDNs may have different URI length limits, but operation safelisting (query whitelist), as a best practice for external-facing production GraphQL apps, can shorten URIs.
总体:
基本上POST 不是幂等操作。 所以你不能用它来缓存。 GET应该是幂等操作,所以常用于缓存。
请参阅HTTP 1.1 RFC 2616 S.9.1。
除了 GET 方法的语义之外:
POST 方法本身在语义上意味着将某些内容发布到资源。 POST 无法缓存,因为如果您执行某件事一次、两次或三次,那么您每次都会更改服务器的资源。 每个请求都很重要,应该传递到服务器。
PUT 方法本身在语义上意味着放置或创建资源。 它是幂等操作,但不会用于缓存,因为同时可能发生 DELETE。
DELETE 方法本身在语义上意味着删除资源。 它是幂等操作,但不会用于缓存,因为同时可能发生 PUT。
关于客户端缓存:
网络浏览器将始终转发您的请求,即使它有来自先前 POST 操作的响应。 例如,您可以间隔几天使用 gmail 发送电子邮件。 它们可能具有相同的主题和正文,但应该发送两封电子邮件。
关于代理缓存:
将消息转发到服务器的代理 HTTP 服务器绝不会缓存除 GET 或 HEAD 请求之外的任何内容。
关于服务器缓存:
默认情况下,服务器不会通过检查其缓存来自动处理 POST 请求。 但是,当然可以将 POST 请求发送到您的应用程序或加载项,并且您可以拥有自己的缓存,当参数相同时可以从中读取。
使资源失效:
检查HTTP 1.1 RFC 2616 S.13.10 表明 POST 方法应该使缓存资源无效。
Overall:
Basically POST is not an idempotent operation. So you cannot use it for caching. GET should be an idempotent operation, so it is commonly used for caching.
Please see section 9.1 of the HTTP 1.1 RFC 2616 S. 9.1.
Other than GET method's semantics:
The POST method itself is semantically meant to post something to a resource. POST cannot be cached because if you do something once vs twice vs three times, then you are altering the server's resource each time. Each request matters and should be delivered to the server.
The PUT method itself is semantically meant to put or create a resource. It is an idempotent operation, but it won't be used for caching because a DELETE could have occurred in the meantime.
The DELETE method itself is semantically meant to delete a resource. It is an idempotent operation, but it won't be used for caching because a PUT could have occurred in the meantime.
Regarding client side caching:
A web browser will always forward your request even if it has a response from a previous POST operation. For example you may send emails with gmail a couple days apart. They may be the same subject and body, but both emails should be sent.
Regarding proxy caching:
A proxy HTTP server that forwards your message to the server would never cache anything but a GET or a HEAD request.
Regarding server caching:
A server by default wouldn't automatically handle a POST request via checking its cache. But of course a POST request can be sent to your application or add-in and you can have your own cache that you read from when the parameters are the same.
Invalidating a resource:
Checking the HTTP 1.1 RFC 2616 S. 13.10 shows that the POST method should invalidate the resource for caching.
如果您确实缓存 POST 响应,则它必须遵循 Web 应用程序的指示。 这就是“对该方法的响应不可缓存,除非响应包含适当的 Cache-Control 或 Expires 标头字段”的含义。
我们可以放心地假设,知道 POST 结果是否幂等的应用程序会决定是否附加必要且正确的缓存控制标头。 如果存在建议允许缓存的标头,则应用程序会告诉您 POST 实际上是超级 GET; 仅当执行幂等操作所需的不必要且不相关(与使用 URI 作为缓存键)数据量时才需要使用 POST。
在此假设下,可以从缓存中提供以下 GET 服务。
如果应用程序未能附加必要且正确的标头来区分可缓存和不可缓存的 POST 响应,则会导致任何无效的缓存结果。
也就是说,每个命中缓存的 POST 都需要使用条件标头进行验证。 这是必需的,以便刷新缓存内容,以避免 POST 的结果在对象的生命周期到期之前不会反映在对请求的响应中。
If you do cache a POST response, it must be at the direction of the web application. This is what is meant by "Responses to this method are not cachable, unless the response includes appropriate Cache-Control or Expires header fields."
One can safely assume that the application, which knows whether or not the results of a POST are idempotent, decides whether or not to attach the necessary and proper cache control headers. If headers that suggest caching is allowed are present, the application is telling you that the POST is, in actuality, a super-GET; that the use of POST was only required due to the amount of unnecessary and irrelevant (to the use of the URI as a cache key) data necessary to perform the idempotent operation.
Following GET's can be served from cache under this assumption.
An application that fails to attach the necessary and correct headers to differentiate between cachable and non-cachable POST responses is at fault for any invalid caching results.
That said, each POST that hits the cache requires validation using conditional headers. This is required in order to refresh the cache content to avoid having the results of a POST not be reflected in the responses to requests until after the lifetime of the object expires.
Mark Nottingham 分析了何时可以缓存 POST 响应。 请注意,后续想要利用缓存的请求必须是 GET 或 HEAD 请求。 另请参阅 http 语义
https://www.mnot.net/blog/2012/09/24/缓存_POST。
Mark Nottingham has analyzed when it is feasible to cache the response of a POST. Note that the subsequent requests that want to take advantage of caching must be GET or HEAD requests. See also http semantics
https://www.mnot.net/blog/2012/09/24/caching_POST.
如果它实际上不会更改您网站上的数据,则它应该是 GET 请求。 即使是表单,你仍然可以将其设置为get请求。 虽然,就像其他人指出的那样,您可以缓存 POST 的结果,但这没有语义意义,因为根据定义,POST 正在更改数据。
If it's something that doesn't actually change data on your site, it should be a GET request. Even if it's a form, you can still set it as a get request. While, like others point out, you could cache the results of a POST, it wouldn't make semantic sense because a POST by definition is changing data.
与 Firefox 27.0 & 2014 年 5 月 19 日,我在 httpfox 上看到这样一行:
00:03:58.777 0.488 657 (393) POST(缓存)text/html https://users.jackiszhp.info/ S4UP
显然,一个post方法的响应是被缓存的,而且也是https的。
难以置信!
With firefox 27.0 & with httpfox, on May 19, 2014, I saw one line of this:
00:03:58.777 0.488 657 (393) POST (Cache) text/html https://users.jackiszhp.info/S4UP
Clearly, the response of a post method is cached, and it is also in https.
Unbelievable!
POST 用于有状态 Ajax。 返回 POST 的缓存响应会破坏通信通道并消除接收消息的副作用。 这非常非常糟糕。 追踪起来也很痛苦。 强烈建议反对。
一个简单的例子是一条消息,作为副作用,支付您本周的工资 10,000 美元。 你不想得到“好吧,成功了!” 上周缓存的页面返回。 其他更复杂的现实案例也会带来类似的欢笑。
POST is used in stateful Ajax. Returning a cached response for a POST defeats the communication channel and the side effects of receiving a message. This is Very Very Bad. It's also a real pain to track down. Highly recommended against.
A trivial example would be a message that, as a side effect, pays your salary $10,000 the current week. You DON'T want to get the "OK, it went through!" page back that was cached last week. Other, more complex real-world cases result in similar hilarity.