为什么浏览器在使用缓存控制的public和max-age后仍然发送请求?

44
我有Amazon S3对象,对于每个对象,我都已经设置了。
Cache-Control: public, max-age=3600000

大约为41天。

我设置了Amazon CloudFront分发,最小TTL也为3600000。

这是清除缓存后的第一次请求。

GET /1.0.8/web-atoms.js HTTP/1.1
Host: d3bhjcyci8s9i2.cloudfront.net
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

响应结果为

HTTP/1.1 200 OK
Content-Type: application/x-javascript
Content-Length: 226802
Connection: keep-alive
Date: Wed, 28 Aug 2013 10:37:38 GMT
Cache-Control: public, max-age=3600000
Last-Modified: Wed, 28 Aug 2013 10:36:42 GMT
ETag: "124752e0d85461a16e76fbdef2e84fb9"
Accept-Ranges: bytes
Server: AmazonS3
Age: 342557
Via: 1.0 6eb330235ca3971f6142a5f789cbc988.cloudfront.net (CloudFront)
X-Cache: Hit from cloudfront
X-Amz-Cf-Id: 92Q2uDA4KizhPk4TludKpwP6Q6uEaKRV0ls9P_TIr11c8GQpTuSfhw==

即使亚马逊明确发送了Cache-Control头信息,Chrome仍然会发出第二个请求,而不是从缓存中读取。

GET /1.0.8/web-atoms.js HTTP/1.1
Host: d3bhjcyci8s9i2.cloudfront.net
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
If-None-Match: "124752e0d85461a16e76fbdef2e84fb9"
If-Modified-Since: Wed, 28 Aug 2013 10:36:42 GMT

问题: 为什么Chrome会发出第二个请求?

过期时间 当我在请求头中添加一个明确的过期时间属性时,这种行为会发生变化。浏览器不会为Expires头发送后续请求,但对于cache-control public,它会发送请求。我的所有S3对象永远不会更改,它们是不可变的,当我们更改文件时,我们将它们作为新对象放置到具有新URL的位置。

页面脚本引用 Chrome有时只会进行几次后续请求,我通过实际在浏览器中输入URL进行了测试。当HTML页面引用脚本时,对于一些后续请求,Chrome会加载缓存的脚本,但偶尔还是会向服务器发送请求。这里没有磁盘大小问题,Chrome具有足够的缓存空间。

问题在于我们每次请求都要付费,我希望S3对象能永久缓存,并应该从缓存中加载,而不应该再连接到服务器。

5个回答

47

当你在Chrome浏览器中按下F5,它会向服务器发送请求。这些请求将使用Cache-Control:max-age=0头部进行。服务器通常会响应304(未修改)状态码。

当你按下Ctrl+F5Shift+F5时,相同的请求被执行,但是带有Cache-Control:no-cache头部,从而强制服务器发送未缓存的版本,通常带有200(OK)状态码。

如果你想确保利用本地浏览器缓存,只需在地址栏中按下Enter即可。


简单而有效的答案。TIL F5Enter发出不同的请求。 - Gras Double
1
三天来一直在苦思冥想。谢谢!我一直按Ctrl + F5,不知道Control:no-cache是从哪里来的,为什么浏览器忽略了我的Cache-Control,或者我做错了什么。天啊,谢谢!还有@GrasDouble,感谢你提供的链接。我知道评论不应该用来表示感谢,但找到你的答案真是一种巨大的解脱。 - Alfonso Nishikawa
1
很棒的答案,我没有检查请求头,你可以运行fetch来检查它是否真的从磁盘获取。例如:fetch('YOUR_URL') - Victor Castro
@DebajitMajumder 那你需要允许客户端这样做。通常使用 Expires 头来实现。 - Oliver Salzburg
使用 Shift+F5,请求中也没有 if-none-match 头。 - maaartinus
显示剩余4条评论

24
如果HTTP响应包含etag条目,条件请求将始终被执行。ETag是一个缓存验证标签。客户端将始终向服务器发送etag,以查看该元素是否已被修改。

2
如果已经有一个HTTP响应,则请求已经发生且“max-age”已被忽略。 - Pablo Fernandez
39
在我的测试中,ETags并没有起作用(我所有的资源都有一个ETag)。我相信这就是你在使用Chrome进行测试的方式。在地址栏上按“回车”是测试缓存的最佳方法。按F5或单击重新加载会发送“max-age = 0”头信息。另请参见:https://dev59.com/rXA75IYBdhLWcg3wPmd8#16510707 - Costa
3
截至目前,Costa的回答仍然适用:如果您刷新页面,Chrome将在请求标头中发送max-age=0。 如果您在URL中按Enter键,则不会发送该标头。 - DarkNeuron
6
在Chrome浏览器版本57.0.2987.133(64位)中,即使来自CloudFront响应的Cache-Control:max-age=300,输入URL并按回车键似乎仍会发送带有条件请求和请求中的max-age=0。基本上,无论我如何发出请求,似乎都无法从浏览器缓存中获取它。我已验证在开发工具中未禁用浏览器缓存。有什么想法吗?这是一张图片。我想知道Content-Type是否与此有关。 - Bradley
5
  1. 当直接在Chrome标签页中输入CloudFront图片的URL时,我想可靠地从浏览器缓存中读取图像的唯一方法是通过“后退/前进”获取该URL。如果我按F5或在URL中按Enter键,我总是看到条件请求并返回状态码304。
  2. 只有当直接访问图像URL时才出现这种情况。当在HTML文档的内容中使用它时,缓存的工作方式如上所述,其中按F5刷新和在URL中按Enter键产生不同的结果。 我只能假设Chrome将直接导航到URL视为应该执行有条件的请求。这是否符合预期?
- Bradley
显示剩余7条评论

10
如果打开Chrome开发者工具(F12),Chrome通常会禁用缓存。
它可以在开发者工具设置中进行控制——位于开发者工具顶部栏右侧的齿轮图标。

6
只有在勾选禁用缓存的框时,F12 才会禁用缓存。当我测试缓存时,我确定缓存是启用的。 - Akash Kava
1
很好的回答。我在服务器上进行了相应的更改,并在打开Dev Tools(F12)时检查结果,但没有看到影响。有太多需要知道的小细节了。我点赞了。 - Soumya Kanti
1
天啊!我没意识到!开发者工具中“禁用缓存”被勾选了 - 唉! - Volksman

2

当您使用自签名证书时,Chrome会添加Cache-control: max-age=0头信息。从HTTPS切换到HTTP将删除此头信息。

Firefox不会添加此头信息。


当我在使用Chrome测试localhost上的响应缓存时,遇到了非常相似的问题——尽管它发送的是nocache而不是max-age=0。当然,结果是一样的。无论如何,很明显它确实会在每个请求中发送这个,但是为什么并不明显。当在本地开发服务器上测试缓存时,这是有用的,因为它几乎肯定会使用自签名证书。 - Jeremy Caney

1
如果您点击刷新按钮加载特定页面或资源,则每次都会发送if-modified-since头请求,如果您改为在新标签页中请求页面/资源或通过脚本或HTML页面中的链接请求,则它将从浏览器缓存中加载页面/资源。

这就是我的情况所发生的事情,也许这是普遍的情况。我不完全确定,但这是我通过挖掘所获得的信息。


在新标签页中打开相同的请求时,Chrome会从浏览器缓存中加载响应,而不是发出额外的请求。感谢分享这个信息。 - Bằng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接