Skip to content

HTTP中的强缓存与协商缓存

浏览器缓存机制

当我们在浏览器中输入一个网址的时候,浏览器会根据URL去请求服务器以获取所需要的数据资源,这一过程可能会导致页面有一段白屏时间,这是因为浏览器需要等待服务器返回数据,而这个过程中,浏览器是处于等待状态的,这样就会导致页面的白屏时间变长,用户体验变差。

因此,当我们需要提高用户体验的时候,我们就可以使用一些缓存技术,如:DNS缓存、CDN缓存、HTTP缓存等,良好的缓存策略可以降低重复资源的请求,降低服务器的开销,提升用户的页面加载速度。

HTTP缓存

基本原理

HTTP缓存是指浏览器在第一次请求服务器资源时,服务器会在响应头中添加一些字段,这些字段会告诉浏览器如何处理这些资源,浏览器会根据这些字段来判断是否需要缓存这些资源,以及缓存多长时间,当浏览器再次请求这些资源时,会根据这些字段来判断是否需要使用缓存。

HTTP缓存分为强缓存和协商缓存,强缓存是指浏览器不需要发送请求到服务器,而是直接从本地缓存中获取资源,协商缓存是指浏览器会发送请求到服务器,由服务器来判断是否使用缓存。

强缓存 🦸

强缓存是指浏览器在第一次请求服务器资源时,服务器会在响应头中添加Cache-ControlExpires字段,这两个字段会告诉浏览器如何处理这些资源,浏览器会根据这些字段来判断是否需要缓存这些资源,以及缓存多长时间,当浏览器再次请求这些资源时,会根据这些字段来判断是否需要使用缓存。

强缓存相关字段

1. pragma

pragma是HTTP/1.1之前遗留的通用首部字段,只有no-cache这一可选值,当no-cache存在时,一定不会命中强缓存。

2. Cache-Control

Cache-Control是HTTP/1.1中用来控制缓存的字段,它可以设置多个值,每个值之间用逗号隔开,常用的值有:

  • public:表示资源可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存。
  • private:表示资源只能被发送请求的客户端缓存,不能被代理服务器(CDN)缓存。
  • no-cache:表示资源可以被缓存,但是每次在使用缓存资源时,都需要向服务器发送请求,由服务器来判断是否使用缓存。
  • no-store:表示资源不可以被缓存,每次都需要向服务器发送请求。
  • max-age:表示资源可以被缓存的最大时间,单位为秒。

TIP

  • 'no-cache'并不意味着不可以进行缓存,而是每次在使用缓存资源时,都需要向服务器发送请求,由服务器来判断缓存是否有效,有效才会使用缓存(协商缓存) - 'no-store'才表示不可以进行缓存
  • Chrome强制刷新(Ctrl+F5)的实现方式为,在请求的首部添加pragma: no-cachecache-control: no-cache实现

image-20230501214334004

  • max-age的值为非0或设置了大于请求日期的Expires才可能命中强缓存,并且只有cache-control不存在no-cache/no-store以及pragma的时候,才会命中强缓存
  • max-age=0的时候,与cache-control: no-cache效果类似
3. Expires

Expires是一个响应头字段,只有当Expires日期前的时候,HTTP缓存有效。并且当cache-controlmax-age的时候,该字段被忽略。

弱缓存(协商缓存)🕵️

弱缓存相关字段

1. Last-Modified/If-Modified-Since

If-Modified-Since是请求头中的一个字段(只能用于GETHead请求),而Last-Modified是响应头中的一个字段。当带着If-Modified-Since的请求发送给服务器的时候,服务器将检查Last-Modified,如果Last-Modified早于或等于If-Modified-Since,则返回304响应,否则重新返回新的资源。

2. ETag/If-None-Match

If-None-Match是请求头的一个字段,ETag是响应头的一个字段,它是根据资源的内容生成的一段Hash值。当带着ETag的请求发送到服务器的时候,服务器会寻找与之匹配的资源,如果有则返回304响应,否则返回200响应与新的资源。

为什么需要ETag

  1. 在没有修改文件内容的情况下,文件最后修改日期可能会变,会导致不必要的请求
  2. 当某些文件在==1秒==内进行了修改,Last-Modified可能监测不到
  3. 某些服务器无法精确获取到文件的修改日期

启发式缓存

​ 当一个网络请求没有expires也没有cache-control,但是有last-modified的时候,浏览器会有一个默认的缓存策略:

(currentTime - Last-Modified) * 0.1

HTTP Heuristic Caching (Missing Cache-Control and Expires Headers) Explained

缓存总流程

整体流程

举个例子🌰

第一次访问本页的时候:

第一次请求资源

可以看到响应头有Cache-Control: no-cache以及ETagLast-Modified,说明,此时为协商缓存。

第二次发送请求的时候,将会比对请求头中的If-None-MatchIf-Modified-Since字段。

image-20230501233831904

可以看到,此时If-None-MatchETag是匹配的,If-Modified-Since也符合Last-Modified的要求,因此,服务器返回304响应,允许使用本地缓存。

状态码区别

  • 200 请求成功,服务器返回全新的资源
  • 200 from memory cache / from disk cache 本地强缓存还在有效期,直接使用本地缓存。 其中,from memory cache表示页面刷新的时候,从内存中获取缓存,from disk cache表示标签页关闭后从磁盘获取缓存
  • 304 请求成功,服务器判断ETagLast-Modified没有过期,告知浏览器使用本地缓存

缓存优先级

oragma > cache-control > expires > Etag > Last-Modified

Released under the MIT License.