什么是强缓存和协商缓存?它们的工作原理是什么?
什么是HTTP缓存?
HTTP缓存是指对于一些重复提交的HTTP请求,每次返回的结果都是一样的,就将请求-响应的数据存储在本地,这样下次就可以直接读取本地的数据,而不用再次通过网络发送请求,提高了HTTP的性能。
避免重复发送HTTP请求的方法就是缓存技术。
在HTTP中有强缓存和协商缓存两种技术。
1.强缓存
1.1定义:
强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
1.2 实现逻辑以及优缺点:
实现字段
强缓存是利用下面这两个HTTP响应头部字段实现的,它们都用来表示资源在客户端缓存的有效期:
- Cache-Control,是一个相对时间;
- Expires,是一个绝对时间;
如果HTTP响应头部同时有Cache-Control和 Expires字段的话,Cache-Control的优先级高于Expires。Cache-control选项更多一些,设置更加精细,所以建议使用Cache-Control来实现强缓存。
具体的实现流程如下:
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在Response头部上Cache-Control,Cache-Control中设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与Cache-Control中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会再次更新Response头部的Cache-Control。
强制缓存的优点:
- 减少网络请求:如果资源没有过期,浏览器不需要再向服务器发送请求,减少了带宽的消耗。
- 提高页面加载速度:如果资源是缓存的,直接从缓存加载会比重新请求更快。
缺点:
- 可能导致资源不更新:如果强制缓存时间过长,用户看到的资源可能是过期的,不会得到最新的更新
2.协商缓存
2.1 定义:
协商缓存顾名思义就是根据协商结果来决定是否使用本地缓存。(如:请求的响状态码是304时,这个是告诉浏览器可以使用本地缓存的资源,这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。)
2.2实现逻辑:
协商缓存有两种实现逻辑:
第一种:请求头部中的If-Modified-Since字段与响应头部中的Last-Modified字段实现
这两个字段的意思是:
-
响应头部中的Last-Modified:标示这个响应资源的最后修改时间;
-
请求头部中的If-Modified-Since:资源最后被更改的时间;
具体实现逻辑
当资源过期了,发现响应头中具有Last-Modified声明,则再次发起请求的时候带上Last-Modified的时间,服务器收到请求后发现有If-Modified-Since则与Last-Modified进行对比,如果If-Modified-Since时间较新,说明资源又被改过,则返回最新资源,同时响应行信息为:HTTP200OK;反之,服务器则返回响应HTTP304(本地重定向)走缓存。由于时间可能会被篡改,这种协商缓存方法并不安全,实际中,第二种协商缓存机制更为常用。
第二种:请求头部中的If-None-Match字段与响应头部中的ETag字段
这两个字段的意思是:
-
响应头部中Etag:唯一标识响应资源;
-
请求头部中的If-None-Match:当资源过期时,浏览器发现响应头里有Etag,则再次向服务器发起请求时,会将请求头If-None-Match值设置为Etag的值。服务器收到请求后进行比对,如果资源没有变化返回304,如果资源变化了返回200。
两种实现方式比较
第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。
如果在第一次请求资源的时候,服务端返回的HTTP响应头部同时有Etag和Last-Modified字段,那么客户端再下一次请求的时候,如果带上了ETag和Last-Modified字段信息给服务端,这时Etag的优先级更高,也就是服务端先会判断Etag是否变化了,如果Etag有变化就不用在判断Last-Modified了,如果Etag没有变化,然后再看Last-Modified。
整体工作原理
- 浏览器请求某个资源时,会附带
If-Modified-Since
或If-None-Match
头部。 - 服务器根据客户端传来的信息检查该资源是否发生变化。- 如果资源没有发生变化,服务器会返回 304 Not Modified,告诉客户端继续使用缓存中的资源。
- 如果资源发生变化,服务器会返回新的资源和
200 OK
状态码。
协商缓存的优点:
- 避免过时数据:服务器可以根据实际情况决定是否返回最新的数据,避免客户端使用过时的缓存。
- 减少带宽消耗:如果资源没有变化,服务器返回 304 响应,客户端不需要重新下载资源,减少了带宽使用。
缺点:
- 相较于强制缓存,增加了额外的请求和响应过程,因为每次都要向服务器验证资源是否有变化。
如何配合使用强制缓存和协商缓存?
- 强制缓存 优先级较高:如果资源没有过期,浏览器直接使用缓存中的内容,不会请求服务器。
- 如果强制缓存已经过期或被清除,协商缓存 会被用来判断资源是否发生变化。协商缓存的目的是在资源没有变化时,避免不必要的数据传输。
例如,浏览器首先检查强制缓存(如 Cache-Control
),如果资源没有过期,直接使用缓存。如果缓存过期,则会进行协商缓存,发送请求给服务器,询问资源是否修改,如果没有修改,服务器返回 304 响应,客户端继续使用缓存中的资源。
强制缓存和协商缓存的区别
特性 | 强制缓存 | 协商缓存 |
---|---|---|
缓存验证方式 | 客户端直接使用缓存,无需与服务器交互 | 客户端请求服务器确认资源是否改变 |
是否请求服务器 | 不会向服务器发送请求,直接使用缓存 | 向服务器发送请求,服务器决定是否返回新资源 |
头部字段 | Cache-Control , Expires | If-Modified-Since , If-None-Match |
响应 | 如果缓存未过期,直接返回缓存资源 | 如果缓存未修改,服务器返回 304 Not Modified |
适用场景 | 对于不频繁变化的资源(如图片、CSS 文件等) | 对于频繁变化的资源,或需要保证最新数据时 |