>[danger]浏览器中强缓存与协商缓存的缓存机制 以下是浏览器强缓存和协商缓存中各自常用的字段: | 强缓存字段 | 协商缓存字段 | |---------------------|-------------------------| | Expires | Last-Modified | | Cache-Control | ETag | | | If-Modified-Since | | | If-None-Match | >[info] 字段含义及作用 | 字段 | 含义及作用 | |---------------------|------------------------------------------------------------------------------------------------------------------------------| | Expires | 指定资源的过期时间。服务器在响应头中设置该字段,告诉浏览器资源的过期时间。如果当前时间小于过期时间,则直接使用缓存的资源,否则重新请求。 | | Cache-Control | 控制缓存行为的指令。通过该字段,服务器可以告知浏览器如何处理缓存。常见的指令包括max-age(缓存有效期)、no-cache(不直接使用缓存,需要协商验证)等。 | | Last-Modified | 资源的最后修改时间。服务器在响应头中设置该字段,标识资源的最后修改时间。浏览器可以将该值存储,并在下次请求时发送给服务器进行协商验证。 | | ETag | 资源的唯一标识符。服务器在响应头中设置该字段,用于唯一标识资源的版本。浏览器可以将该值存储,并在下次请求时发送给服务器进行协商验证。 | | If-Modified-Since | 上次请求资源时的Last-Modified值。浏览器在请求头中设置该字段,用于与服务器进行协商验证,判断资源是否有更新。如果没有更新,服务器返回304 Not Modified状态码。 | | If-None-Match | 上次请求资源时的ETag值。浏览器在请求头中设置该字段,用于与服务器进行协商验证,判断资源是否有更新。如果没有更新,服务器返回304 Not Modified状态码。 | | 200 OK | 表示请求成功,返回的是新的资源。若服务器返回该状态码,表明资源未使用缓存,浏览器会将新的资源保存到缓存中,并使用该资源。 | | 304 Not Modified | 表示资源未发生变化,可以使用缓存的旧资源。如果服务器确定资源未修改,返回该状态码,浏览器会从缓存中加载资源,并继续使用该资源。 | >[info]技术解读 >强缓存 在发送 http 请求下载资源之前首先检查强缓存。使用的字段在 http/1.0 和 http/1.1 中分别是 **Expires** 和 **Cache-Control**。 ##### Expires http/1.0 中使用的字段是 Expires 即过期时间,存在于服务器返回的响应头中,浏览器在这个过期时间前再次请求同一资源时将直接从缓存里面获取数据,无需再次发送 http 请求。事例如下: ``` Expires: Wed, 21 Oct 2020 07:28:00 GMT ``` 使用此字段的缺陷是服务器的时间和浏览器的时间可能不一致,这样服务器返回的过期时间就不一定是准确的。因此这种方式在 http/1.1 中被废弃。 ##### Cache-Control http/1.1 中使用的字段是 Cache-Control, 也存在于服务器返回的响应头中,但采用过期时长而非具体过期时间点,示例如下: ``` Cache-Control:public, max-age=86400 ``` 表示在响应返回后的 86400 秒也就是 24 小时之内可以直接使用缓存。 public 是另一个缓存指令,表示响应可以被任何对象(包括发送请求的客户端、代理服务器等等)缓存,即使是通常不可缓存的内容。此外,还可组合如下的缓存指令: private: 表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。 no-cache: 跳过当前的强缓存检查,发送 http 请求,即直接进入 协商缓存阶段。 no-store: 缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。 注意:当 Expires 和 Cache-Control 同时存在的时候,Cache-Control 会被优先考虑。 >协商缓存 当强缓存失效,浏览器在 http 请求头中加入某些字段,服务端根据这些字段确定浏览器是否能够使用缓存,这就是协商缓存。这样的字段有两对:**Last-Modified**/**If-Modified-Since**和 **ETag**/**If-None-Match**。 ##### **Last-Modified**/**If-Modified-Since** - 浏览器第一次给服务端发送请求后,服务器会在响应头中加上 Last-Modified 这个字段和值。 - 浏览器接收到这个字段并在第二次给服务端发送请求时用 If-Modified-Since 字段携带该值。 - 服务端接收到后会和服务端中该资源的最后修改时间作对比, - 如果请求头中的这个值小于最后修改时间,则返回新的资源,否则返回304,告诉浏览器直接用缓存。 ##### **ETag**/**If-None-Match** - ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,一旦文件内容有改动,这个值就会变化。 - 服务器通过响应头把这个值传给浏览器,浏览器接收到ETag的值,会在下次请求时将这个值放到请求头 If-None-Match 字段中,然后发给服务器。 - 服务端接收到 If-None-Match 后,会跟服务器上该资源的 ETag 进行比对,如果两者不一样,返回新的资源,否则返回304,告诉浏览器直接用缓存。 - 另外,在 ETag 和 If-Match 请求头的帮助下,可以检测到"空中碰撞"的编辑冲突。 > **Last-Modified**/**If-Modified-Since**和 **ETag**/**If-None-Match**的比较 - 比较这两种方式,精确度上 ETag 要优于 Last-Modified。因为 Last-Modified 的最小单位是秒,假如文件在一秒内改变了多次,这个时候 Last-Modified 的值并没有变化。 - 性能上 Last-Modified 要优于 ETag,因为 Last-Modified 仅仅只是记录一个时间点,而 Etag 需要根据文件的具体内容生成哈希值。