前言
HTTP
缓存不管是在面试中,还是实际开发中都是重中之重。了解 HTTP
缓存不仅可以轻松自如应对面试,而且也是在实际开发中对性能优化不可或缺的手段。
缓存分类
浏览器第一次请求资源时,必须请求所有的资源,然后根据响应的 header
内容来决定,如何缓存资源。一般而言缓存可以分为强缓存和协商缓存两种。
强缓存
当客户端缓存所要请求的数据时。客户端直接从缓存数据获取数据。当客户端没有缓存所请求的数据时,客户端的才会从服务端获取数据。
协商缓存
又称对比缓存,客户端会先从缓存数据中获取到一个缓存数据的标识,得到标识后请求服务端验证是否失效(新鲜),如果没有失效服务端会返回 304,此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据。
缓存字段
服务器响应的 header 中会用两个缓存的字段:Expires
和Cache-Control
。
1、Expires
指定缓存到期 GMT
的绝对时间,如果设了 max-age
,max-age
就会覆盖 expires
。如果expires
到期需要重新请求。
2、Cache-Control
Cache-Control
: 这个是 http 1.1
中为了弥补 Expires
缺陷新加入的。
对已缓存的内容进行控制:
Cache-control: public
表示缓存的版本可以被代理服务器或者其他中间服务器识别。
Cache-control: private
意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
Cache-control: no-cache
强制浏览器提交一个 http 请求到源服务器进行确认。http
请求没有减少,会减少一个响应体(文件内容), 这种个选项类似弱缓存
其他相关控制字段:
max-age
: 指定缓存过期的相对时间秒数,max-ag=0
或者是 负值
,浏览器会在对应的缓存中把Expires
设置为1970-01-01 08:00:00
。
no-store
: 告诉浏览器在任何情况下都不要进行cache
,不在本地保留拷贝。
must-revalidate
: 强制浏览器严格遵守你设置的 cache
规则。
资源验证
验证是否能使用缓存(协商缓存策略
)主要有两种方式:
1、Last-Modified
:最后一次修改时间
配合 If-Modified-Since
和If-UnModified-Since
使用
对比上次修改时间以验证资源是否需要重新修改
2、Etag
: 数据签名
配合 If-Match
或者 If-Non-Match
使用
对比资源的签名判断是否使用缓存
而这里 Etag
主要为了解决 Last-Modified
无法解决的一些问题:
1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since
能检查到的粒度是 s 级的,这种修改无法判断 (或者说UNIX
记录 MTIME
只能精确到秒);
3、某些服务器不能精确的得到文件的最后修改时间。
缓存状态码
200 OK (from cache)
是浏览器没有跟服务器确认,直接用了浏览器缓存;
304 Not Modified
是浏览器和服务器多确认了一次缓存有效性,再用的缓存。
304 Not Modified
比 200 OK (from cache)
慢,指的是浏览器还向服务器确认了下 If-Not-Modified
,才用的缓存。
浏览器中的操作对缓存的影响:
强制刷新 – 当按下 ctrl+F5
来刷新页面的时候, 浏览器将绕过各种缓存(本地缓存和协商缓存), 直接让服务器返回最新的资源;
普通刷新 – 当按下 F5
来刷新页面的时候, 浏览器将绕过本地缓蹲来发送请求到服务器, 此时, 协商缓存是有效的
回车或转向 – 当在地址栏上输入回车或者按下跳转按钮的时候, 所有缓存都生效