浏览器缓存

1.浏览器缓存

1. 对浏览器的缓存机制的理解

浏览器缓存的全过程:

  • 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;
  • 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;
  • 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;
  • 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
  • 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;

浏览器缓存_第1张图片

很多网站的资源后面都加了版本号,这样做的目的是:每次升级了 JS 或 CSS 文件后,为了防止浏览器进行缓存,强制改变版本号,客户端浏览器就会重新下载新的 JS 或 CSS 文件 ,以保证用户能够及时获得网站的最新更新。

2. 协商缓存和强缓存的区别

(1)强缓存

使用强缓存策略时,如果缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求。

强缓存策略可以通过两种方式来设置,分别是 http 头信息中的 Expires 属性和 Cache-Control 属性。

(1)服务器通过在响应头中添加 Expires 属性,来指定资源的过期时间。在过期时间以内,该资源可以被缓存使用,不必再向服务器发送请求。这个时间是一个绝对时间,它是服务器的时间,因此可能存在这样的问题,就是客户端的时间和服务器端的时间不一致,或者用户可以对客户端时间进行修改的情况,这样就可能会影响缓存命中的结果。

(2)Expires 是 http1.0 中的方式,因为它的一些缺点,在 HTTP 1.1 中提出了一个新的头部属性就是 Cache-Control 属性,它提供了对资源的缓存的更精确的控制。它有很多不同的值,

Cache-Control可设置的字段:

  • public:设置了该字段值的资源表示可以被任何对象(包括:发送请求的客户端、代理服务器等等)缓存。这个字段值不常用,一般还是使用max-age=来精确控制;
  • private:设置了该字段值的资源只能被用户浏览器缓存,不允许任何代理服务器缓存。在实际开发当中,对于一些含有用户信息的HTML,通常都要设置这个字段值,避免代理服务器(CDN)缓存;
  • no-cache:设置了该字段需要先和服务端确认返回的资源是否发生了变化,如果资源未发生变化,则直接使用缓存好的资源;
  • no-store:设置了该字段表示禁止任何缓存,每次都会向服务端发起新的请求,拉取最新的资源;
  • max-age=:设置缓存的最大有效期,单位为秒;
  • s-maxage=:优先级高于max-age=,仅适用于共享缓存(CDN),优先级高于max-age或者Expires头;
  • max-stale[=]:设置了该字段表明客户端愿意接收已经过期的资源,但是不能超过给定的时间限制。

一般来说只需要设置其中一种方式就可以实现强缓存策略,当两种方式一起使用时,Cache-Control 的优先级要高于 Expires。

no-cache和no-store很容易混淆:

  • no-cache 是指先要和服务器确认是否有资源更新,在进行判断。也就是说没有强缓存,但是会有协商缓存;
  • no-store 是指不使用任何缓存,每次请求都直接从服务器获取资源。
(2)协商缓存

如果命中强制缓存,我们无需发起新的请求,直接使用缓存内容,如果没有命中强制缓存,如果设置了协商缓存,这个时候协商缓存就会发挥作用了。

上面已经说到了,命中协商缓存的条件有两个:

  • max-age=xxx 过期了
  • 值为no-store

使用协商缓存策略时,会先向服务器发送一个请求,如果资源没有发生修改,则返回一个 304 状态,让浏览器使用本地的缓存副本。如果资源发生了修改,则返回修改后的资源。

协商缓存也可以通过两种方式来设置,分别是 http 头信息中的** Etag** 和** Last-Modified **属性。

(1)服务器通过在响应头中添加 Last-Modified 属性来指出资源最后一次修改的时间,当浏览器下一次发起请求时,会在请求头中添加一个 If-Modified-Since 的属性,属性值为上一次资源返回时的 Last-Modified 的值。当请求发送到服务器后服务器会通过这个属性来和资源的最后一次的修改时间来进行比较,以此来判断资源是否做了修改。如果资源没有修改,那么返回 304 状态,让客户端使用本地的缓存。如果资源已经被修改了,则返回修改后的资源。使用这种方法有一个缺点,就是 Last-Modified 标注的最后修改时间只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,那么文件已将改变了但是 Last-Modified 却没有改变,这样会造成缓存命中的不准确。

(2)因为 Last-Modified 的这种可能发生的不准确性,http 中提供了另外一种方式,那就是 Etag 属性。服务器在返回资源的时候,在头信息中添加了 Etag 属性,这个属性是资源生成的唯一标识符,当资源发生改变的时候,这个值也会发生改变。在下一次资源请求时,浏览器会在请求头中添加一个 If-None-Match 属性,这个属性的值就是上次返回的资源的 Etag 的值。服务接收到请求后会根据这个值来和资源当前的 Etag 的值来进行比较,以此来判断资源是否发生改变,是否需要返回资源。通过这种方式,比 Last-Modified 的方式更加精确。

当 Last-Modified 和 Etag 属性同时出现的时候,Etag 的优先级更高。使用协商缓存的时候,服务器需要考虑负载平衡的问题,因此多个服务器上资源的 Last-Modified 应该保持一致,因为每个服务器上 Etag 的值都不一样,因此在考虑负载平衡时,最好不要设置 Etag 属性。

总结:

强缓存策略和协商缓存策略在缓存命中时都会直接使用本地的缓存副本,区别只在于协商缓存会向服务器发送一次请求。它们缓存不命中时,都会向服务器发送请求来获取资源。在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则浏览器返回最新的资源给浏览器。

3. 为什么需要浏览器缓存?

对于浏览器的缓存,主要针对的是前端的静态资源,最好的效果就是,在发起请求之后,拉取相应的静态资源,并保存在本地。如果服务器的静态资源没有更新,那么在下次请求的时候,就直接从本地读取即可,如果服务器的静态资源已经更新,那么我们再次请求的时候,就到服务器拉取新的资源,并保存在本地。这样就大大的减少了请求的次数,提高了网站的性能。这就要用到浏览器的缓存策略了。

所谓的浏览器缓存指的是浏览器将用户请求过的静态资源,存储到电脑本地磁盘中,当浏览器再次访问时,就可以直接从本地加载,不需要再去服务端请求了。

使用浏览器缓存,有以下优点:

  • 减少了服务器的负担,提高了网站的性能
  • 加快了客户端网页的加载速度
  • 减少了多余网络数据传输

2.强缓存

强缓存(Strong Caching) 是浏览器缓存机制中的一种,旨在通过设置特定的HTTP头来告诉浏览器在一定时间内直接使用缓存的资源,而无需向服务器发起请求。强缓存可以显著提高页面加载速度和性能。以下是关于强缓存的详细说明:

基本概念

  1. 强缓存:
    • 强缓存是一种高效的缓存机制,浏览器在缓存资源时会记录一个过期时间。
    • 在这个过期时间之前,浏览器会直接使用缓存的资源,而不会向服务器发起请求。
  2. 缓存控制头:
    • 强缓存主要通过以下两个HTTP头来控制:
      • Cache-Control
      • Expires

缓存控制头

1. Cache-Control

Cache-Control 是一个通用的缓存控制头,可以设置多种缓存策略。对于强缓存,常用的指令包括:

  • max-age=:
    • 指定资源在缓存中的最大有效时间(以秒为单位)。
    • 例如,Cache-Control: max-age=3600 表示资源在缓存中有效时间为1小时。
  • s-maxage=:
    • 类似于 max-age,但仅适用于共享缓存(如CDN)。
    • 例如,Cache-Control: s-maxage=3600 表示共享缓存中资源的有效时间为1小时。
  • public:
    • 允许任何缓存存储资源,包括共享缓存。
    • 例如,Cache-Control: public, max-age=3600
  • private:
    • 仅允许私有缓存(如浏览器缓存)存储资源,不允许共享缓存存储。
    • 例如,Cache-Control: private, max-age=3600
2. Expires

Expires 头指定资源的过期日期和时间,是一个绝对时间点。

  • 格式:
    • Expires 头的值是一个HTTP日期时间字符串。
    • 例如,Expires: Wed, 21 Oct 2020 07:28:00 GMT

强缓存的工作流程

  1. 请求资源:
    • 用户首次请求资源时,服务器返回资源内容以及相应的缓存控制头(如 Cache-ControlExpires)。
  2. 存储资源:
    • 浏览器根据缓存控制头将资源存储在缓存中,并记录资源的过期时间。
  3. 后续请求:
    • 当用户再次请求同一资源时,浏览器会检查缓存中该资源的过期时间。
    • 如果当前时间在资源的过期时间之前,浏览器会直接使用缓存的资源,而不会向服务器发起请求。
    • 如果当前时间超过资源的过期时间,浏览器会向服务器发起请求以获取最新资源。

示例

使用 Cache-Control

假设服务器返回以下响应头:

HTTP/1.1 200 OK
Cache-Control: max-age=3600
Content-Type: image/png
Content-Length: 12345
... (image data)
  • 首次请求:
    • 浏览器请求资源,服务器返回资源内容并设置 Cache-Control: max-age=3600
    • 浏览器将资源存储在缓存中,并记录过期时间为当前时间加上3600秒。
  • 后续请求:
    • 如果在3600秒内再次请求该资源,浏览器会直接使用缓存的资源,不会向服务器发起请求。
    • 如果超过3600秒再次请求该资源,浏览器会向服务器发起请求以获取最新资源。
使用 Expires

假设服务器返回以下响应头:

HTTP/1.1 200 OK
Expires: Wed, 21 Oct 2020 07:28:00 GMT
Content-Type: image/png
Content-Length: 12345
... (image data)
  • 首次请求:
    • 浏览器请求资源,服务器返回资源内容并设置 Expires: Wed, 21 Oct 2020 07:28:00 GMT
    • 浏览器将资源存储在缓存中,并记录过期时间为 Wed, 21 Oct 2020 07:28:00 GMT
  • 后续请求:
    • 如果在 Wed, 21 Oct 2020 07:28:00 GMT 之前再次请求该资源,浏览器会直接使用缓存的资源,不会向服务器发起请求。
    • 如果超过 Wed, 21 Oct 2020 07:28:00 GMT 再次请求该资源,浏览器会向服务器发起请求以获取最新资源。

强缓存的优点

  1. 提高性能:
    • 减少向服务器发起的请求数量,降低服务器负载。
    • 加快页面加载速度,提高用户体验。
  2. 减少带宽消耗:
    • 通过使用缓存的资源,减少数据传输量,节省带宽。
  3. 简化缓存管理:
    • 强缓存机制简单且易于实现,不需要复杂的缓存验证逻辑。

强缓存的缺点

  1. 内容更新问题:
    • 如果资源内容更新,但缓存未过期,浏览器会继续使用旧的缓存资源。
    • 可能导致用户看到过时的内容。
  2. 缓存控制头设置不当:
    • 如果 Cache-ControlExpires 设置不当,可能导致缓存过期时间过长或过短,影响用户体验和性能。

结合使用 Cache-ControlExpires

为了更好地控制缓存行为,可以同时使用 Cache-ControlExpires 头。Cache-Control 提供更灵活的控制选项,而 Expires 提供绝对时间点。

示例
HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
Expires: Wed, 21 Oct 2020 07:28:00 GMT
Content-Type: image/png
Content-Length: 12345
... (image data)
  • Cache-Control: max-age=3600, public: 资源在缓存中有效时间为1小时,允许任何缓存存储资源。
  • Expires: Wed, 21 Oct 2020 07:28:00 GMT: 资源的过期时间为 Wed, 21 Oct 2020 07:28:00 GMT

总结

  • 强缓存 是一种高效的缓存机制,通过 Cache-ControlExpires 头控制资源的缓存行为。
  • Cache-Control: 提供灵活的缓存控制选项,如 max-ages-maxage
  • Expires: 指定资源的绝对过期时间。
  • 工作流程: 浏览器根据缓存控制头存储资源,并在缓存未过期时直接使用缓存的资源。
  • 优点: 提高性能、减少带宽消耗、简化缓存管理。
  • 缺点: 内容更新问题、缓存控制头设置不当。
    通过合理设置强缓存头,可以显著提高网页的加载速度和性能。如果你有其他问题或需要进一步的解释,请随时告诉我!

3.协商缓存

协商缓存(Conditional Caching) 是浏览器缓存机制中的一种,用于在缓存资源过期或不确定是否为最新版本时,与服务器进行协商以确定是否可以使用缓存的资源。协商缓存通过设置特定的HTTP头来实现,确保浏览器在使用缓存资源之前验证资源的最新性。以下是关于协商缓存的详细说明:

基本概念

  1. 协商缓存:
    • 协商缓存是一种缓存机制,当缓存的资源过期或浏览器不确定资源是否为最新版本时,浏览器会向服务器发送一个验证请求。
    • 服务器根据请求中的验证头来决定是否返回最新的资源或确认缓存的资源是最新的。
  2. 缓存控制头:
    • 协商缓存主要通过以下两个HTTP头来控制:
      • ETagIf-None-Match
      • Last-ModifiedIf-Modified-Since

缓存控制头

1. ETagIf-None-Match
  • ETag** (Entity Tag)**:
    • 服务器返回资源时,生成一个唯一的标识符(通常是资源的哈希值),用于标识资源的版本。
    • 例如,ETag: "123456789"
  • If-None-Match:
    • 浏览器在后续请求中,将之前收到的 ETag 值包含在 If-None-Match 头中,请求服务器验证资源是否为最新版本。
    • 例如,If-None-Match: "123456789"
2. Last-ModifiedIf-Modified-Since
  • Last-Modified:
    • 服务器返回资源时,指定资源最后修改的时间戳。
    • 例如,Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
  • If-Modified-Since:
    • 浏览器在后续请求中,将之前收到的 Last-Modified 时间戳包含在 If-Modified-Since 头中,请求服务器验证资源是否为最新版本。
    • 例如,If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT

协商缓存的工作流程

  1. 首次请求:
    • 用户首次请求资源时,服务器返回资源内容以及相应的缓存控制头(如 ETagLast-Modified)。
  2. 存储资源:
    • 浏览器根据缓存控制头将资源存储在缓存中,并记录资源的唯一标识符或最后修改时间。
  3. 后续请求:
    • 当用户再次请求同一资源时,浏览器会检查缓存中该资源的唯一标识符或最后修改时间。
    • 浏览器将这些信息包含在请求头中(如 If-None-MatchIf-Modified-Since),向服务器发起验证请求。
  4. 服务器验证:
    • 服务器收到验证请求后,根据请求头中的信息来判断资源是否为最新版本。
    • 如果资源未被修改,服务器返回 304 Not Modified 状态码,表示缓存的资源是最新的。
    • 如果资源已被修改,服务器返回最新的资源内容以及相应的缓存控制头。

示例

使用 ETagIf-None-Match
  1. 首次请求:
GET /resource HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
ETag: "123456789"
Content-Type: image/png
Content-Length: 12345
... (image data)
  1. 后续请求:
GET /resource HTTP/1.1
Host: example.com
If-None-Match: "123456789"
  1. 服务器验证:
    • 如果资源未被修改:
HTTP/1.1 304 Not Modified
- 如果资源已被修改:
HTTP/1.1 200 OK
ETag: "987654321"
Content-Type: image/png
Content-Length: 12345
... (new image data)
使用 Last-ModifiedIf-Modified-Since
  1. 首次请求:
GET /resource HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
Content-Type: image/png
Content-Length: 12345
... (image data)
  1. 后续请求:
GET /resource HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
  1. 服务器验证:
    • 如果资源未被修改:
HTTP/1.1 304 Not Modified
- 如果资源已被修改:
HTTP/1.1 200 OK
Last-Modified: Thu, 22 Oct 2020 08:28:00 GMT
Content-Type: image/png
Content-Length: 12345
... (new image data)

协商缓存的优点

  1. 确保资源最新:
    • 通过与服务器协商,确保浏览器使用的是最新版本的资源,避免显示过时的内容。
  2. 减少数据传输:
    • 当资源未被修改时,服务器返回 304 Not Modified 状态码,不传输资源内容,节省带宽。
  3. 提高性能:
    • 减少不必要的数据传输,提高页面加载速度和用户体验。

协商缓存的缺点

  1. 额外的请求开销:
    • 每次请求都会发送验证头,增加了网络开销。
    • 尽管请求体为空,但仍然需要建立TCP连接和发送HTTP头。
  2. 复杂性:
    • 需要服务器正确生成和验证 ETagLast-Modified 头,增加了服务器的复杂性。
  3. 时间戳精度:
    • Last-Modified 头的时间戳精度有限,可能无法精确反映资源的修改时间。

结合使用强缓存和协商缓存

为了更好地管理缓存,可以结合使用强缓存和协商缓存。强缓存用于在缓存未过期时直接使用缓存的资源,协商缓存用于在缓存过期时验证资源的最新性。

示例
HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
ETag: "123456789"
Content-Type: image/png
Content-Length: 12345
... (image data)
  • Cache-Control: max-age=3600, public: 资源在缓存中有效时间为1小时,允许任何缓存存储资源。
  • ETag: "123456789": 资源的唯一标识符。

总结

  • 协商缓存 是一种缓存机制,通过 ETagIf-None-MatchLast-ModifiedIf-Modified-Since 头来验证资源的最新性。
  • ETag** 和 **If-None-Match: 使用唯一标识符来验证资源。
  • Last-Modified** 和 **If-Modified-Since: 使用最后修改时间来验证资源。
  • 工作流程: 浏览器在缓存过期或不确定资源是否为最新版本时,向服务器发送验证请求,服务器根据请求头决定是否返回最新的资源或确认缓存的资源是最新的。
  • 优点: 确保资源最新、减少数据传输、提高性能。
  • 缺点: 额外的请求开销、复杂性、时间戳精度问题。
    通过合理结合强缓存和协商缓存,可以显著提高网页的加载速度和性能。如果你有其他问题或需要进一步的解释,请随时告诉我!

4.怎么设置协商缓存和强缓存

设置协商缓存和强缓存通常在后端进行。前端(客户端)主要是接收和处理这些缓存控制头,而不会直接设置这些头。后端通过在HTTP响应头中添加适当的缓存控制信息来指示浏览器如何缓存资源。

后端设置强缓存

强缓存通过 Cache-ControlExpires 头来设置。以下是如何在不同后端框架中设置这些头的示例。

1. Node.js (Express)
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static(path.join(__dirname, 'public'), {
    setHeaders: (res, path, stat) => {
        res.set('Cache-Control', 'public, max-age=3600'); // 1 hour
        res.set('Expires', new Date(Date.now() + 3600 * 1000).toUTCString());
    }
}));
app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000');
});

后端设置协商缓存

协商缓存通过 ETagLast-Modified 头来设置。以下是如何在不同后端框架中设置这些头的示例。

1. Node.js (Express)
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
app.get('/resource', (req, res) => {
    const filePath = path.join(__dirname, 'public', 'resource.png');
    const stat = fs.statSync(filePath);
    const lastModified = stat.mtime.toUTCString();
    const etag = `"${stat.size}-${stat.mtime.getTime()}"`;
    if (req.headers['if-none-match'] === etag || req.headers['if-modified-since'] === lastModified) {
        return res.status(304).send();
    }
    res.set('ETag', etag);
    res.set('Last-Modified', lastModified);
    res.sendFile(filePath);
});
app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000');
});

总结

  • 强缓存 通过 Cache-ControlExpires 头设置,指示浏览器在缓存未过期时直接使用缓存的资源。
  • 协商缓存 通过 ETagIf-None-MatchLast-ModifiedIf-Modified-Since 头设置,指示浏览器在缓存过期时与服务器协商资源的最新性。
  • 设置位置: 通常在后端设置这些缓存控制头,前端接收并处理这些头。
  • 示例: 提供了在 Node.js (Express)、Python (Flask) 和 Java (Spring Boot) 中设置强缓存和协商缓存的代码示例。
    通过合理设置这些缓存控制头,可以显著提高网页的加载速度和性能。如果你有其他问题或需要进一步的解释,请随时告诉我!

你可能感兴趣的:(缓存,前端,edge浏览器)