浏览器缓存
我们都知道,缓存的存在是为了节约通信成本、减少服务器负担、提高网页的响应速度,但也导致了资源文件过时的问题,所以这方面也有相应的策略,保证缓存的作用尽可能地得到发挥。
浏览器缓存分为强缓存与协商缓存。简单而言,强缓存是没有过期的缓存,而协商缓存是过期了、但经过鉴定还能够继续使用的缓存。
强缓存
HTTP 响应报文的头中可以使用 Expires
与 Cache-Control
两个字段来标识资源的缓存时间:
- Expires 属于 HTTP/1.0 的规范,使用绝对时间的 GMT 格式字符串表示缓存失效时间。
- Cache-Control 则来自 HTTP/1.1,使用
max-age
值或者特殊值来设置缓存策略。
Expires 最大的缺点就是因为其是一个绝对时间,当服务器与客户端的时间偏差较大时,会导致缓存变得混乱。
Cache-Control 则采用相对时间,解决了这个问题。例如:
Cache-Control: max-age=3600
代表着资源的有效期是3600秒,接收到资源后的3600秒内无需重新访问服务器获取该资源,直接复用该缓存即可。
除了设置 max-age
,还有以下几个常用的设置值:
- no-cache:不使用强缓存,但可以进行缓存协商。
- no-store:禁止游览器缓存数据,彻底不使用缓存。
- public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。
- private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
为了兼容性,Cache-Control
与 Expires
可以在服务端配置同时启用,但同时启用的时候 Cache-Control
的优先级更高。
协商缓存
所谓协商,就是浏览器对于是否要使用该资源的缓存,都会先和服务器先进行沟通。
在 HTTP/1.0 中,第一次响应返回的头中会带有 Last-Modified
字段,用来表示资源的最后一次修改日期。
如在客户端的缓存过期后,客户端向服务端请求该文件时就会带上 If-Modified-Since
字段,其值为之前所收到的 Last-Modified
值。
如果服务端将其与文件进行对比后发现没有修改,则只返回 304 响应码而不携带资源,说明该资源仍然能够继续使用,从而达到节约带宽的效果。
但因为以下的原因,在 HTTP/1.1 中,这两个字段又有了新的版本:
- 有些文件会进行周期性的更改,但是他的内容并不改变,仅仅是改变了文件的最后修改时间
- 如果文件的修改频率很高,1秒钟内修改了多次,那么原本的表示法无法精确到1秒以内
- 某些服务器不能精确的得到文件的最后修改时间
于是对应地,出现了 ETag
与 If-None-Match
字段。
ETag
是文件的唯一校验码,如果文件有进行修改,那么 ETag
就会发生变动。如果客户端发来的 If-None-Match
值与服务端文件的 ETag
比对不一致,则说明缓存已过期,需要重新发送文件。
HTTP 规范中并没有规定
ETag
应该用什么算法来生成,比较理想的是用哈希,但是因为这样非常消耗服务器资源,所以许多服务器一般是使用Last-Modified
+Content-Length
的十六进制表示连在一起来表示ETag
。
某次请求得到的示例:
部分请求头的字段:
:authority: ceynri.cn
:method: GET
cache-control: max-age=0
if-modified-since: Mon, 13 Apr 2020 06:23:12 GMT
if-none-match: W/"5e940550-3a60"
部分响应头的字段:
date: Tue, 14 Apr 2020 15:08:25 GMT
etag: W/"5e940550-3a60"
last-modified: Mon, 13 Apr 2020 06:23:12 GMT
status: 304
用户使用 F5 刷新页面时,会无视强缓存进行协商缓存的流程;如果使用 Ctrl + F5 强制刷新页面,则强制重新获取资源。
← 从URL到页面加载完成 DNS 协议 →