在现代 Web 应用中,HTTP 缓存是提升性能和优化资源使用的关键技术。本文将基于 Chrome 浏览器的实际运行场景,分析其在请求中涉及的缓存策略及工作机制。
实践场景描述
假设我们访问一个网站 https://example.com,其首页有多个静态资源(例如 HTML 文件、CSS 样式表、JavaScript 脚本和图片)。为方便分析,我们重点关注以下几个请求:
index.htmlstyle.cssapp.jslogo.png
我们使用 Chrome 的 开发者工具(DevTools) 来捕捉网络请求,观察缓存策略的具体实现。
缓存策略分析
1. 初次请求
在浏览器首次加载网站时:
- Cache-Control 和 Expires 头会在响应中返回,定义资源的缓存有效期。
- 没有任何缓存资源时,所有请求都需要从服务器获取。
示例请求:
GET /index.html HTTP/1.1
Host: example.com
服务器响应:
HTTP/1.1 200 OK
Content-Type: text/html
Cache-Control: max-age=3600, public
分析:
- Cache-Control: max-age=3600 表示资源的有效期为 3600 秒,在这段时间内,浏览器可以直接从缓存读取资源,而无需向服务器重新请求。
- 如果没有缓存策略或者策略设置为
no-store,浏览器会每次都请求服务器。
2. 再次请求:浏览器如何决定是否从缓存加载?
当用户刷新页面时,浏览器会根据缓存头信息判断是否使用缓存。
场景 1:缓存仍然有效
当资源未过期时(例如 3600 秒内),浏览器直接从本地缓存加载资源,无需发起网络请求。
场景 2:缓存已过期
当资源过期时,浏览器会发起条件请求,利用 ETag 或 Last-Modified 头,与服务器验证缓存资源的有效性。
示例请求:
GET /style.css HTTP/1.1
Host: example.com
If-None-Match: "abc123"
服务器响应:
HTTP/1.1 304 Not Modified
分析:
- 浏览器通过
If-None-Match携带 ETag(实体标签)向服务器验证资源是否发生改变。 - 服务器返回
304 Not Modified,浏览器继续使用本地缓存的资源,从而节省带宽和时间。
3. 强制刷新(Ctrl+F5 或 Cmd+Shift+R)
当用户执行强制刷新时,浏览器会跳过缓存并直接请求服务器。
示例请求:
GET /app.js HTTP/1.1
Host: example.com
Cache-Control: no-cache
分析:
- 强制刷新时,浏览器在请求头中添加
Cache-Control: no-cache,要求服务器忽略缓存验证。 - 服务器将重新返回最新版本的资源。
4. 缓存策略的实际效果
为了更清晰地分析缓存策略,我们可以在 Chrome DevTools 中查看以下字段:
- Size:显示资源从网络加载还是从缓存加载。
- Status Code:观察返回的 HTTP 状态码(如 200、304)。
- Cache-Control、Expires 等头信息:确定缓存的具体设置。
示例:
| 资源名称 | Size | Status Code | Cache 状态 |
|---|---|---|---|
index.html | 1.2 KB | 200 | 从网络加载(首次) |
style.css | 15 KB | 304 | 从缓存加载 |
app.js | 25 KB | 200 | 强制刷新 |
logo.png | (cached) | - | 本地缓存未请求 |
优化建议
- 静态资源设置长缓存时间:
对于不频繁更新的资源(如图片和字体),可以使用Cache-Control: max-age=31536000, immutable来实现长期缓存。 - 使用版本号或哈希值管理文件更新:
通过文件名中的版本号或哈希值(如app.12345.js),可以有效控制缓存失效的问题。 - 对动态内容启用缓存验证:
使用ETag和Last-Modified,确保动态内容不会因缓存而变得过时。 - 按需应用强制刷新策略:
对于敏感信息页面(如登录页面),可以使用Cache-Control: no-store防止缓存。