1. 什么是HTTP缓存策略
HTTP 缓存是一种提高网页性能和用户体验的重要技术,它可以减少网络流量,降低服务器负载,加快响应速度,节省用户流量等。HTTP 缓存的基本原理是,当客户端(如浏览器)第一次请求一个资源(如网页、图片、样式表等)时,服务器会返回该资源,并在响应头中添加一些缓存相关的信息,如 Cache-Control、Last-Modified、ETag 等。客户端会根据这些信息来决定是否将该资源缓存在本地(如浏览器缓存)。当客户端再次请求该资源时,如果本地缓存还有效(fresh),则直接从缓存中读取该资源,而不需要再向服务器发送请求;如果本地缓存已经过期(stale),则客户端会向服务器发送一个验证请求(如 If-Modified-Since、If-None-Match 等),询问该资源是否有更新。服务器会根据验证请求中的信息来判断该资源是否有更新,如果没有更新,则返回一个 304 Not Modified 的状态码,告诉客户端可以继续使用本地缓存;如果有更新,则返回一个 200 OK 的状态码,并返回最新的资源和缓存信息。这样就可以实现缓存的有效利用和及时更新。
2. 具体分析
为了更好地理解 HTTP 缓存的工作原理和效果,我们选择使用 edge 浏览器来访问一个具体的网站,并使用开发者工具来查看其涉及的请求中的缓存策略。我们选择 百度 作为例子,因为其页面中包含了多种类型的资源,如 HTML、CSS、JS、图片等,可以较为全面的提供案例。我们可以按照以下步骤来进行分析:
-
打开 edge 浏览器,并在地址栏输入 [www.baidu.com/] ,然后按回车键。
-
打开开发者工具(按 F12 键或者右键点击页面空白处选择“检查”),并切换到“网络”选项卡。
-
刷新页面(按 F5 键或者点击浏览器工具栏上的刷新按钮),并观察网络面板中显示的请求列表。
-
在网络面板中,我们可以看到每个请求的名称、状态码、类型、大小、时间等信息。我们可以点击某个请求,在右侧面板中查看其详细信息,包括请求头、响应头、预览、响应等。
-
我们可以根据不同的状态码来区分不同的缓存策略:
- 如果状态码是 200 OK,并且大小列显示了具体的字节数(如 12.3 KB),则表示该请求是从服务器获取了最新的资源,并没有使用本地缓存。
- 如果状态码是 200 OK,并且大小列显示了 (from memory cache) 或者 (from disk cache),则表示该请求是从本地缓存中读取了资源,并没有向服务器发送请求。
- 如果状态码是 304 Not Modified,并且大小列显示了 (from memory cache) 或者 (from disk cache),则表示该请求是向服务器发送了验证请求,服务器返回了 304 状态码,告诉客户端可以继续使用本地缓存。
-
我们还可以根据不同的类型来区分不同的资源:
- 如果类型是 document,则表示该请求是获取网页的 HTML 文档。
- 如果类型是 stylesheet,则表示该请求是获取网页的 CSS 样式表。
- 如果类型是 script,则表示该请求是获取网页的 JS 脚本。
- 如果类型是 image,则表示该请求是获取网页的图片。
- 如果类型是 font,则表示该请求是获取网页的字体文件。
- 如果类型是 xhr,则表示该请求是通过 AJAX 发送的异步请求。
-
此外,我们还可以根据响应头中的缓存相关的信息来分析不同的缓存策略:
- 如果响应头中有 Cache-Control 字段,则表示该资源使用了基于 age 的缓存策略,即根据资源的最大有效期(max-age)来判断是否过期。例如,Cache-Control: max-age=31536000 表示该资源的最大有效期为一年,即一年内不会过期。
- 如果响应头中有 Last-Modified 和 ETag 字段,则表示该资源使用了基于验证的缓存策略,即根据资源的最后修改时间(Last-Modified)或者实体标签(ETag)来判断是否更新。例如,Last-Modified: Tue, 22 Feb 2022 22:22:22 GMT 和 ETag: “5d8c72a5-2c” 表示该资源在 2022 年 2 月 22 日 22 点 22 分 22 秒被修改过,且其实体标签为 “5d8c72a5-2c”。当客户端再次请求该资源时,会在请求头中添加 If-Modified-Since: Tue, 22 Feb 2022 22:22:22 GMT 和 If-None-Match: “5d8c72a5-2c” 字段,询问服务器该资源是否有更新。如果没有更新,则服务器会返回 304 状态码,否则会返回 200 状态码和最新的资源。
- 如果响应头中没有任何缓存相关的信息,则表示该资源没有使用任何缓存策略,即每次都需要从服务器获取最新的资源。
下面我们以几个具体的请求为例,来分析其缓存策略:
- 请求 [www.baidu.com/] ,状态码为 200 OK,类型为 document,大小为 12.3 KB。从响应头中我们可以看到,该请求没有使用任何缓存策略,即每次都需要从服务器获取最新的 HTML 文档。这是合理的,因为 HTML 文档通常是动态生成的,可能会随时变化,所以不能缓存。
- 请求 [pss.bdstatic.com/static/supe…] ,状态码为 200 OK,类型为 image,大小为 (from disk cache)。从响应头中我们可以看到,该请求使用了基于 age 的缓存策略,其最大有效期为一年(Cache-Control: max-age=31536000)。这意味着该图片在一年内不会过期,所以可以直接从本地缓存中读取,而不需要再向服务器发送请求。这是合理的,因为图片通常不会经常变化,所以可以长时间缓存。
- 请求 [www.baidu.com/sugrec?&pro…] ,状态码为 200 OK,类型为 xhr,大小为 1.4 KB。从响应头中我们可以看到,该请求使用了基于验证的缓存策略,并且禁止了共享缓存(Cache-Control: no-cache, private)。这意味着该资源每次都需要向服务器发送验证请求,并且禁止了共享缓存(Cache-Control: no-cache, private)。这意味着该资源每次都需要向服务器发送验证请求,并且不能被中间代理(如 CDN)缓存。这是合理的,因为该资源是通过 AJAX 发送的异步请求,用于获取用户输入的搜索建议,这是一个动态变化和用户相关的数据,所以不能缓存或者共享。从请求头中我们可以看到,该请求使用了 ETag 字段来进行验证,例如 ETag: “5d8c72a5-2c”。当客户端再次请求该资源时,会在请求头中添加 If-None-Match: “5d8c72a5-2c” 字段,询问服务器该资源是否有更新。如果没有更新,则服务器会返回 304 状态码,否则会返回 200 状态码和最新的资源。
- 请求 [www.baidu.com/favicon.ico] ,状态码为 304 Not Modified,类型为 image,大小为 (from disk cache)。从响应头中我们可以看到,该请求使用了基于验证的缓存策略,并且设置了一个较长的最大有效期(Cache-Control: max-age=31536000, public)。这意味着该资源在一年内不会过期,但是每次都需要向服务器发送验证请求。这是合理的,因为该资源是网站的图标文件,通常不会经常变化,但是也需要及时更新。从请求头中我们可以看到,该请求使用了 If-Modified-Since 字段来进行验证,例如 If-Modified-Since: Tue, 22 Feb 2022 22:22:22 GMT。当客户端再次请求该资源时,服务器会根据该字段来判断该资源是否有更新。如果没有更新,则服务器会返回 304 状态码,告诉客户端可以继续使用本地缓存;如果有更新,则服务器会返回 200 状态码和最新的资源。