缓存技术介绍
背景:
具有一些重复性的HTTP请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了,这样的话 HTTP/1.1 的性能肯定肉眼可见的提升。
所以,避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段。
HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
强制缓存:
指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
如图所示,返回的状态码为200,但在size项中标识的是from disk cache
,这就是使用了强制缓存。
强制缓存主要利用以下两个HTTP响应头部字段实现的,都用来表示资源在客户端缓存的有效期。
Cache-Control:
请求&响应头,缓存控制字段,是一个相对时间。
值 | 作用 |
---|---|
no-store | 所有内容不缓存 |
no-cache | 缓存,但使用缓存之前需要请求服务器判断资源是否是最新 |
max-age=x(秒) | 请求缓存后的x秒内不在发起请求 |
s-maxage=x(秒) | 代理服务器请求源站缓存后x秒内不在发起请求,只对CDN有效 |
public | 客户端和代理服务器(CDN)都可缓存 |
private | 只有客户端可以缓存 |
Expires:
响应头 | 代表缓存资源过期时间,由服务器提供 | HTTP1.0
的属性,比max-age
优先级低 | 是一个绝对时间。
强制缓存流程:
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在
Response
头部加上Cache-Control
,Cache-Control
中设置了过期时间大小; - 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与
Cache-Control
中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器; - 服务器再次收到请求后,会再次更新
Response
头部的Cache-Control
。
协商缓存:
当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。
协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存。
两种响应头部:
①请求头部中的 If-Modified-Since
字段与响应头部中的 Last-Modified
字段实现;
②请求头部中的 If-None-Match
字段与响应头部中的 ETag
字段
第一种:
响应头部 Last-Modified :标识这个响应资源的最后修改时间;
请求头部 If-Modified-Since:
- 当资源过期了,发现响应头部中具有
Last-Modified
声明,则再次发起请求的时候带上Last-Modified
的时间; - 服务器收到请求后发现有
If-Modified-Since
则于被请求的资源最后修改时间进行对比(Last-Modified
); - 如果最后修改时间较新,说明资源又被修改过,则返回最新资源,HTTP 200 OK;
- 如果最后修改时间较旧,说明资源无新修改,响应HTTP 304 走缓存。
响应头部Last-Modified
:标识这个响应资源的最后修改时间。
第二种:
响应头部中的 Etag :唯一标识响应资源。
请求资头部中的 If-None-Match:
- 当资源过期时,浏览器发现响应头里有Etag,则再次向服务器发起请求时,会将请求头
If-None-Match
值设置为Etag的值。 - 服务器收到请求后进行对比,如果值相等,返回304状态码,不会返回资源;如果值变化了,说明资源变化了,返回200状态码,并返回资源。
- 如果浏览器收到了304请求响应状态码,则会从本地缓存中加载资源,否则更新资源。
两方法的不同总结:
第一种方法是基于时间来实现的; 第二种方法是基于一个唯一标识实现的,后者相对来说能更加准确的判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。
如果HTTP响应头部同时有Etag和Last-Modified字段时,Etag的优先级更高,会首先判断Etag是否变化,再看Last-Modified。
注意:
协商缓存的这两个字段都是需要配合强制缓存中的Cache-Control字段来使用,只有在未命中强制缓存时,才能发起带有协商缓存字段的请求。