浏览器缓存 request/response 没有任何 Cache-Control header

Browser caching request/response without any Cache-Control header

我遇到了 SPA 网络应用程序和 REST API 后端的浏览器缓存问题。我可以在打开开发人员工具的情况下在 Firefox 和 Safari 上重现它:我确保未禁用缓存。

当我第一次访问一个特定页面时,它只是从 REST API 中获取并显示 object,我使用“硬刷新”(CMD+R on Mac ).我看到以下 headers:

第一个请求:

Host: localhost:5000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: application/json, text/plain, */*
Accept-Language: en,it;q=0.7,fr;q=0.3
Accept-Encoding: gzip, deflate, br
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Referer: http://localhost:3000/literature/sde5e-zeb98
Cookie: ...
If-Modified-Since: Fri, 10 Jul 2020 16:19:24 GMT
If-None-Match: "2"
Cache-Control: max-age=0

(注意 Cache-Control header,由于硬刷新而自动添加)

回复:

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 6128
ETag: "2"
Last-Modified: Fri, 10 Jul 2020 16:19:24 GMT
Link: <https://localhost:5000/api/documents/sde5e-zeb98>; rel="self"
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 52
X-RateLimit-Reset: 1594398279
Retry-After: 60
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31556926; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: Content-Type, ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Access-Control-Allow-Credentials: true
Vary: Origin
Server: Werkzeug/1.0.1 Python/3.6.7
Date: Fri, 10 Jul 2020 16:23:38 GMT

请求按预期到达后端,我正在记录它。后端 returns ETag + Last modified headers,但没有其他缓存 headers(例如 max-age)。我希望浏览器始终访问后端。

当我没有点击硬刷新,而是简单地在网站上导航到另一个页面,然后再次导航到该页面(而不是通过后退按钮)时,就会出现问题,这基本上是网站的正常使用。 我希望浏览器每次都向后端执行请求,后端 returns ETag 和 200/304 状态代码,浏览器相应地使用客户端缓存(后端的 ETag 计算是正确的)。 问题是请求甚至没有到达后端,没有执行请求,没有后端命中,我不明白为什么。我可以在 Firefox 中看到 Transferred 列中的值 cached

她的要求:

Host: localhost:5000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: application/json, text/plain, */*
Accept-Language: en,it;q=0.7,fr;q=0.3
Accept-Encoding: gzip, deflate, br
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Referer: http://localhost:3000/literature/sde5e-zeb98
Cookie: ...

(没有Cache-Control header,没错,应该是正常行为)

缓存响应(无后端命中):

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 6128
ETag: "2"
Last-Modified: Fri, 10 Jul 2020 16:19:24 GMT
Link: <https://localhost:5000/api/documents/sde5e-zeb98>; rel="self"
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 52
X-RateLimit-Reset: 1594398445
Retry-After: 60
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31556926; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: Content-Type, ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Access-Control-Allow-Credentials: true
Vary: Origin
Server: Werkzeug/1.0.1 Python/3.6.7
Date: Fri, 10 Jul 2020 16:26:24 GMT

我试图了解哪个 header 正在停止浏览器执行请求。我没有设置 Cache-Control header。 我怀疑这可能是 Vary header 的问题,但欢迎提供任何提示。

知道如何调试浏览器缓存请求的原因吗? header 哪里错了?谢谢!

缺少Cache-ControlExpires并不意味着缓存被禁用;这意味着浏览器可以自由实施自己的缓存策略。如RFC 7234所述:

Since origin servers do not always provide explicit expiration times, a cache MAY assign a heuristic expiration time when an explicit time is not specified, employing algorithms that use other header field values (such as the Last-Modified time) to estimate a plausible expiration time.

你真正想要的caching policyCache-Control: no-cache,所以return那个。

The response may be stored by any cache, even if the response is normally non-cacheable. However, the stored response MUST always go through validation with the origin server first before using it.