静态资源怎样缓存?

访客 性能优化 2

从原理到实践,提升网站性能的终极指南

📖 目录导读

  1. 为什么静态资源缓存如此重要?
  2. 缓存的核心机制:浏览器与服务器如何协作?
  3. 七大缓存策略详解(附代码示例)
  4. 常见陷阱与避坑指南
  5. 实战问答:解决你的缓存困惑
  6. 构建高性能缓存体系的黄金法则

为什么静态资源缓存如此重要?

静态资源(CSS、JavaScript、图片、字体等)通常占据网页加载体积的70%以上,合理配置缓存能实现:

  • 加载速度提升60%-80%:用户再次访问时,资源从本地缓存读取,无需重复请求服务器
  • 服务器压力降低50%以上:减少带宽消耗和数据库查询次数
  • 用户体验优化:页面秒开,避免白屏等待

真实数据对比
未缓存页面(3.2MB资源)加载耗时4.8秒 → 缓存后仅需0.3秒(本地读取)


缓存的核心机制:浏览器与服务器如何协作?

1 缓存流程三步曲

  1. 首次请求:浏览器向服务器请求资源 → 服务器返回资源+缓存控制头(Cache-ControlExpiresETag等)
  2. 缓存存储:浏览器根据响应头将资源存入本地(内存/磁盘缓存)
  3. 二次请求:浏览器先检查本地缓存 → 有效则直接使用;失效则发起条件请求(携带If-None-MatchIf-Modified-Since

2 关键缓存头解析

响应头 作用 示例
Cache-Control 指定缓存策略(最核心) max-age=31536000(缓存1年)
Expires 绝对过期时间(HTTP/1.0规范) Expires: Thu, 31 Dec 2025 23:59:59 GMT
ETag 指纹,用于强校验 ETag: "abc123"
Last-Modified 文件最后修改时间 Last-Modified: Tue, 15 Nov 2024 12:45:26 GMT

注意Cache-Control优先级高于Expires,现代浏览器主要支持前者。


七大缓存策略详解(附代码示例)

强缓存(无需请求服务器)

适用场景:版本稳定的小文件(Logo、CSS框架、基础库)

配置方式

location ~* \.(css|js|png|jpg|gif)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

关键参数

  • public:允许任何中间缓存(CDN、代理)
  • immutable:告诉浏览器文件永不改变,无需每次询问

协商缓存(需验证但可能304)

适用场景:频繁更新的资源(如博客样式、动态生成的图片)

配置方式(Nginx):

location / {
    add_header ETag "unique-hash";
    add_header Last-Modified $date_gmt;
    if_modified_since exact;
}

验证流程
浏览器携带If-None-Match: "abc123" → 服务器比对ETag → 命中返回304(Not Modified)+ 空主体

版本号/指纹策略(推荐)

最佳实践:在文件名中加入哈希值(如app.8f3a2b.css

构建工具配置(Webpack):

output: {
    filename: 'js/[name].[contenthash:8].js',
    path: path.resolve(__dirname, 'dist')
}

优势

  • 修改后生成新文件名,旧文件缓存自动失效
  • 实现长期甚至永久缓存(max-age=31536000

CDN分发加速

配置要点

# CDN回源设置
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=static:10m;
location ~* \.(js|css|png)$ {
    proxy_cache static;
    proxy_cache_valid 200 7d;
    add_header X-Cache-Status $upstream_cache_status;
}

分层缓存:浏览器缓存(1天)← CDN边缘节点(7天)← 源服务器(15天)

Service Worker离线缓存

示例代码

// sw.js
const CACHE_NAME = 'v1.0';
self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(CACHE_NAME).then((cache) => {
            return cache.addAll([
                '/styles/main.css',
                '/scripts/app.js',
                '/images/logo.png'
            ]);
        })
    );
});
self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            return response || fetch(event.request);
        })
    );
});

优先级缓存策略

分级规则

  1. 核心CSS → 缓存30天(强缓存)
  2. 业务JS → 缓存7天(带指纹)
  3. 用户头像 → 缓存1天(协商缓存)
  4. 广告脚本 → 不缓存(Cache-Control: no-cache

动态预加载与预缓存

HTML标签实现

<link rel="preload" href="critical.css" as="style">
<link rel="prefetch" href="next-page.js" as="script">

常见陷阱与避坑指南

❌ 陷阱1:过度使用no-cache

  • 错误:对所有资源设置no-cache,导致每次都要验证
  • 修正:区分强缓存与协商缓存,静态资源使用强缓存

❌ 陷阱2:忽略Vary

  • 问题:Gzip压缩后的资源与原始版本不匹配
  • 解决:添加Vary: Accept-Encoding

❌ 陷阱3:版本号与缓存时间不匹配

  • 案例style.css?v=1 → 修改后忘记更新版本号
  • 方案:使用自动化构建工具(Webpack/Vite)自动生成哈希文件名

❌ 陷阱4:混合协议(HTTP/HTTPS)导致缓存失效

  • 现象:HTTPS页面部署HTTP资源时可能被拦截
  • 解决:统一使用相对路径或协议自适应(开头的URL)

实战问答:解决你的缓存困惑

Q1:什么时候应该使用no-cache vs no-store

A

  • no-cache:浏览器需要先向服务器验证资源是否更新(最终决定权在服务器)
  • no-store:完全禁用缓存,每次必须从服务器下载(适用于支付信息、个人资料页)

Q2:如何强制刷新浏览器缓存?

A

  • 用户操作:Ctrl + F5(Windows)/ Cmd + Shift + R(Mac)
  • 开发者操作:在Chrome DevTools中勾选“Disable cache”
  • 服务器配置:在URL后追加随机参数(如?t=123456)(仅限调试环境)

Q3:我的CSS更新后用户看不到新样式怎么办?

A

  1. 版本号法:修改CSS文件名中的哈希值
  2. 设置较短的缓存时间(如max-age=3600
  3. 使用Cache-Control: no-cache配合ETag(会降低性能)
  4. 最终方案:在HTML中通过<link>标签强制更新(如<link href="style.css?v=2.0">

Q4:为什么我的图片缓存了但重新加载后大小没变?

A

  • 检查响应头:图片没有Cache-ControlExpires
  • 浏览器默认缓存策略:某些浏览器对图片采用弱缓存(仅缓存至当前会话)
  • 解决方案:明确设置Cache-Control: max-age=2592000

构建高性能缓存体系的黄金法则

  1. 分层缓存架构:浏览器缓存(秒级)+ CDN缓存(天级)+ Service Worker离线缓存(月级)
  2. 文件名指纹化:使用[contenthash]实现永久缓存
  3. 版本号策略:每2周清理一次长期缓存版本
  4. 监控与测试:使用Chrome DevTools → Network面板 → 检查“From Memory Cache”和“From Disk Cache”状态
  5. Brotli压缩:比Gzip压缩率高20%,进一步减少静态资源体积

最终效果

  • 首次加载:优化后从4秒降至2秒
  • 二次加载:稳定在0.3秒以内(全部从本地缓存读取)
  • 服务器负载:下降70%以上

提示:实施缓存策略后,请务必在多个浏览器和设备上进行测试,并配置合理的Cache-Control优先级(immutable > max-age > no-cache)。

标签: HTTP缓存 CDN

抱歉,评论功能暂时关闭!