是否可以在HTTP中缓存POST方法?

fly*_*ire 146 post http http-caching

使用非常简单的缓存语义:如果参数相同(当然URL相同),那么它就是一个命中.那可能吗?推荐的?

Dio*_*lis 93

如果使用适当的头,则9.5节(POST)中相应的RFC 2616允许缓存对POST消息的响应.

除非响应包含适当的Cache-Control或Expires头字段,否则对此方法的响应不可缓存.但是,303(请参阅其他)响应可用于指示用户代理检索可缓存资源.

请注意,相同的RFC在第13节(在HTTP中缓存)中明确指出缓存必须在POST 请求后使相应的实体无效.

某些HTTP方法必须导致缓存使实体无效.这可以是Request-URI引用的实体,也可以是Location或Content-Location头(如果存在).这些方法是:

  - PUT
  - DELETE
  - POST
Run Code Online (Sandbox Code Playgroud)

我不清楚这些规范如何允许有意义的缓存.

  • HTTPbis 对此进行了澄清;有关摘要,请参阅 http://www.mnot.net/blog/2012/09/24/caching_POST。 (4认同)
  • 源服务器是HTTP和处理POST请求的应用程序之间的代理.该应用程序超出了HTTP边界,它可以随心所欲.如果缓存对特定的POST请求有意义,则可以自由缓存,就像操作系统可以缓存磁盘请求一样. (2认同)
  • Diomidis,您认为缓存POST请求不会是HTTP的说法是错误的。有关详细信息,请参见reBoot的答案。在顶部显示错误的答案不是很有帮助,但这就是民主的运作方式。如果您同意reBoot,则更正您的答案会很好。 (2认同)
  • 尤金(Eugene),我们是否可以同意:a)POST应该使缓存的实体无效(根据第13.10节),以便例如后续的GET必须获取fersh副本,以及b)可以缓存POST的响应(根据9.5节),以便例如随后的POST可以收到相同的响应吗? (2认同)

小智 65

根据RFC 2616第9.5节:

"对POST方法的响应不可缓存,除非响应包含适当的Cache-Control或Expires头字段."

所以,是的,你可以缓存POST请求响应,但只有当它到达时才有适当的头.在大多数情况下,您不希望缓存响应.但在某些情况下 - 例如,如果您没有在服务器上保存任何数据 - 这是完全合适的.

请注意,然而,无论标头如何,许多浏览器(包括当前的Firefox 3.0.10)都不会缓存POST响应.在这方面,IE表现得更聪明.

现在,我想澄清一些关于RFC 2616 S. 13.10的混淆.对于URI的POST方法不会"使用于缓存的资源无效",正如一些人在此处所述.它使该URI的先前缓存版本过时,即使其缓存控制头指示较长持续时间的新鲜度.

  • "使缓存资源无效"和"使URI过时的缓存版本"之间有什么区别?您是说允许服务器缓存POST响应但客户端可能不会? (3认同)
  • “使 URI 的缓存版本失效”适用于您对 `GET` 和 `POST` 请求使用相同 URI 的情况。如果您是位于客户端和服务器之间的缓存,您会看到 `GET /foo` 并缓存响应。接下来你会看到 `POST /foo` 那么你必须*使来自 `GET /foo` 的缓存响应无效,即使 `POST` 响应不包含任何缓存控制标头 *因为它们是相同的 URI*,因此下一个 `GET /foo` 将不得不重新验证,即使原始标头表明缓存仍然有效(如果你没有看到 `POST /foo` 请求) (3认同)
  • +1 reBoot,感谢您解释标题问题并纠正有关13.10的错误陈述.令人惊讶的是,这些错误的答案得到了如此多的赞成. (2认同)
  • ``但是在某些情况下 - 例如如果您没有在服务器上保存任何数据 - 这是完全合适的。```。那么这样的 POST API 首先有什么意义呢? (2认同)

Bri*_*ndy 33

总体:

基本上POST不是幂等操作.所以你不能用它来缓存.GET应该是幂等操作,因此它通常用于缓存.

请参阅HTTP 1.1 RFC 2616 S. 9.1的9.1节.

除了GET方法的语义之外:

POST方法本身在语义上意味着将某些东西发布到资源.POST无法缓存,因为如果你做了一次vs两次而不是三次,那么你每次都在改变服务器的资源.每个请求都很重要,应该发送到服务器.

PUT方法本身在语义上意味着放置或创建资源.它是一个幂等操作,但它不会用于缓存,因为在此期间可能发生了DELETE.

DELETE方法本身在语义上意味着删除资源.它是幂等操作,但它不会用于缓存,因为PUT可能同时发生.

关于客户端缓存:

即使Web浏览器具有先前POST操作的响应,它也将始终转发您的请求.例如,您可以在几天内发送带有Gmail的电子邮件.它们可能是相同的主题和正文,但两封电子邮件都应该发送.

关于代理缓存:

将消息转发到服务器的代理HTTP服务器永远不会缓存除GET或HEAD请求之外的任何内容.

关于服务器缓存:

默认情况下,服务器不会通过检查其缓存自动处理POST请求.但是当然可以将POST请求发送到您的应用程序或加载项,并且您可以拥有自己的缓存,这些缓存可以在参数相同时读取.

使资源无效:

检查HTTP 1.1 RFC 2616 S. 13.10表明POST方法应该使资源无效以进行缓存.

  • "基本上POST不是幂等操作.所以你不能用它来进行缓存." 这是错的,并没有真正意义,请参阅reBoot的细节答案.不幸的是,我还不能投票,否则我会. (6认同)

tim*_*998 14

如果您想知道是否可以缓存发布请求,并尝试研究该问题的答案,您可能不会成功。搜索“缓存发布请求”时,第一个结果是这个 StackOverflow 问题。

答案是缓存应该如何工作、缓存如何根据 RFC 工作、缓存应该如何根据 RFC 工作以及缓存在实践中如何工作的混淆。让我们从 RFC 开始,演示浏览器的实际工作方式,然后讨论 CDN、GraphQL 和其他相关领域。

RFC 2616

根据 RFC,POST 请求必须使缓存无效:

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
Run Code Online (Sandbox Code Playgroud)

这种语言表明 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.
Run Code Online (Sandbox Code Playgroud)

尽管有这种语言,设置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.
Run Code Online (Sandbox Code Playgroud)

这有什么意义?好吧,您不是在缓存POST请求,而是在缓存资源。

POST 响应正文只能为对同一资源的后续 GET 请求进行缓存。在 POST 响应中设置LocationorContent-Location标头以传达正文代表的资源。因此,缓存 POST 请求的唯一技术上有效的方法是针对同一资源的后续 GET。

正确答案是:

  • “是的,RFC 允许您将后续 GET 的 POST 请求缓存到同一资源”
  • “不,RFC 不允许您为后续 POST 缓存 POST 请求,因为 POST 不是幂等的,必须写入服务器”

尽管 RFC 允许缓存对同一资源的请求,但在实践中,浏览器和 CDN 并未实现此行为,并且不允许您缓存 POST 请求。

资料来源:

浏览器行为演示

给定以下示例 JavaScript 应用程序 (index.js):

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
Run Code Online (Sandbox Code Playgroud)

并给出以下示例网页(index.html):

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.
Run Code Online (Sandbox Code Playgroud)

安装 NodeJS、Express,然后启动 JavaScript 应用程序。在浏览器中打开网页。尝试几个不同的场景来测试浏览器行为:

  • 单击“触发 GET 请求”每次都会显示相同的“计数”(HTTP 缓存有效)。
  • 单击“触发 POST 请求”每次都会触发不同的计数(POST 的 HTTP 缓存不起作用)。
  • 单击“触发 GET 请求”、“触发 POST 请求”和“触发 GET 请求”显示 POST 请求使 GET 请求的缓存无效。
  • 单击“触发 POST 请求”然后单击“触发 GET 请求”显示浏览器不会缓存后续 GET 请求的 POST 请求,即使 RFC 允许它。

这表明,即使您可以设置响应头Cache-ControlContent-Location响应头,也无法让浏览器缓存 HTTP POST 请求。

我必须遵循 RFC 吗?

浏览器行为是不可配置的,但如果您不是浏览器,则不一定受 RFC 规则的约束。

如果您正在编写应用程序代码,则没有什么可以阻止您显式缓存 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.
Run Code Online (Sandbox Code Playgroud)

CDN、代理和网关也不一定必须遵循 RFC。例如,如果您使用 Fastly 作为 CDN,Fastly 允许您编写自定义 VCL逻辑来缓存 POST 请求

我应该缓存 POST 请求吗?

是否应缓存 POST 请求取决于上下文。

例如,您可以在底层查询是幂等的情况下使用 POST 查询 Elasticsearch 或 GraphQL。在这些情况下,根据用例缓存响应可能有意义也可能没有意义。

在 RESTful API 中,POST 请求通常会创建资源,不应缓存。这也是RFC对POST不是幂等操作的理解。

图形语言

如果您使用 GraphQL 并需要跨 CDN 和浏览器进行 HTTP 缓存,请考虑使用GET 方法而不是POST发送查询是否满足您的要求。需要注意的是,不同的浏览器和 CDN 可能有不同的 URI 长度限制,但操作安全列表(查询白名单)作为面向外部的生产 GraphQL 应用程序的最佳实践,可以缩短 URI。

  • 我见过的最好的答案之一 (2认同)

小智 7

如果您确实缓存了POST响应,则它必须位于Web应用程序的方向上.这就是"除非响应包含适当的Cache-Control或Expires头字段,否则对此方法的响应不可缓存."

可以安全地假设知道POST的结果是否是幂等的应用程序决定是否附加必要和适当的缓存控制头.如果存在允许缓存的标题,则应用程序会告诉您POST实际上是超级GET; 因为执行幂等操作所必需的数据(对于使用URI作为缓存键)所需的数量,才需要使用POST.

在这个假设下,可以从缓存中提供GET.

无法附加必要且正确的标头以区分可缓存和不可缓存的POST响应的应用程序对于任何无效的缓存结果都是错误的.

也就是说,每个命中缓存的POST都需要使用条件头进行验证.这是为了刷新缓存内容以避免在对象的生命周期到期之前不会在请求的响应中反映POST的结果.


dsc*_*ten 5

Mark Nottingham 分析了何时可以缓存 POST 的响应。请注意,后续要利用缓存的请求必须是 GET 或 HEAD 请求。另见http语义

POST 不处理已识别状态的表示,100 次中有 99 次。但是,有一种情况是这样;当服务器通过设置与请求 URI 相同的 Content-Location 标头来特意说明此 POST 响应是其 URI 的表示时。发生这种情况时,POST 响应就像是对同一 URI 的 GET 响应;它可以被缓存和重用——但仅限于未来的 GET 请求。

https://www.mnot.net/blog/2012/09/24/caching_POST