当浏览器请求某个资源时,会经过以下几个缓存阶段:
- DNS缓存:浏览器会先查询本地DNS缓存,如果在本地缓存中找到了该域名的IP地址映射,则会跳过DNS解析过程,直接访问该IP地址的服务器。
- 第一次请求:若没有命中本地DNS缓存,则会进行DNS解析,得到服务器的IP地址,然后向服务器发送请求,此时服务器会返回资源内容、缓存策略等信息。
- 强缓存:浏览器在收到服务器响应时,会先进行强缓存判断。如果命中强缓存,浏览器直接使用本地缓存,不会发送请求到服务器。强缓存可以通过两种方式实现:
- Expires:在服务器响应头中添加Expires字段,指定资源的过期时间。浏览器会将该时间和本地时间进行比较,如果本地时间小于过期时间,就使用本地缓存。
- Cache-Control:在响应头中添加Cache-Control字段和对应的指令,例如max-age、no-store、public等,来控制缓存的行为。其中,max-age指定了缓存的最大时长(单位为秒),no-store指定禁止缓存,public指定缓存适用于所有用户。 -Expires 字段的控制缓存时间机制,是基于 HTTP/1.0 协议的。在 HTTP/1.0 中,浏览器在每次请求时都会发送完整的 HTTP 头信息,没有缓存技术,在这种情况下,Expires 可以用来设置资源的过期时间,使得浏览器可以更好地控制缓存。 但是,在 HTTP/1.1 中,由于缓存技术的引入,Expires 相对失去了使用价值,并被 Cache-Control 所取代。Cache-Control 可以控制缓存的过期时间、缓存时效检查以及缓存机制等,相较于 Expires 无疑更加强大和实用。 当 Cache-Control 与 Expires 都在 HTTP 响应头中同时出现时,Cache-Control 会覆盖 Expires 的缓存时间设置,HTTP 客户端会默认使用 Cache-Control 的缓存设置进行缓存管理。 总结来说,Expires 和 Cache-Control 用于控制浏览器缓存
- 协商缓存:如果未命中强缓存,则会向服务器发起请求,服务器会根据Last-Modified和ETag等信息,在响应头中返回相应信息。浏览器会将这些信息保存到本地,并在下次请求时带上相关的参数,带给服务端进行协商缓存:
- Last-Modified机制:服务器在响应头中添加Last-Modified字段,表示资源的最后修改时间。浏览器在下次请求时,在请求头中添加If-Modified-Since字段,带上上次请求时返回的Last-Modified信息。服务器收到请求后发现If-Modified-Since和资源的Last-Modified信息相同,就会返回304 Not Modified状态码,并在响应头中添加缓存策略。此时浏览器可以直接使用本地缓存。
- ETag机制:服务器在响应头中添加ETag字段,表示资源的唯一标识。浏览器在下次请求时,在请求头中添加If-None-Match字段,带上上次请求时返回的ETag信息。服务器收到请求后判断If-None-Match和资源的ETag信息相同,就会返回304 Not Modified状态码,并在响应头中添加缓存策略。此时浏览器可以直接使用本地缓存。 -Last-Modified 和 ETag 也是 HTTP/1.1 协议中常用的标识资源的一些元数据信息。它们都用来控制协商缓存的过程,但是优先级上略有不同 -ETag 的优先级高于 Last-Modified。这是因为 Last-Modified 只是精确到秒的粒度,如果两个资源在同一秒内被修改,则它们的 Last-Modified 值就相同,无法识别具体的修改。而 ETag 是一个 hash 值,只有当内容发生修改时才会改变,比 Last-Modified 更精细,能够更好地控制协商缓存。如果两者同时存在,服务端通常会优先判断 ETag 值是否相等,相等则返回 304 响应状态码,继续使用缓存;否则才会进行 Last-Modified 判断。