阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 资源缓存策略设计

资源缓存策略设计

作者:陈川 阅读数:42432人阅读 分类: 性能优化

资源缓存策略设计

资源缓存是提升应用性能的关键手段之一,通过合理利用浏览器缓存机制,减少重复请求和网络传输时间。缓存策略需要根据资源类型、更新频率以及业务需求进行针对性设计。

浏览器缓存机制

浏览器缓存主要分为强缓存和协商缓存两类:

  1. 强缓存:直接使用本地副本,不发送请求到服务器。通过Cache-ControlExpires头控制。
  2. 协商缓存:每次请求时向服务器验证资源是否过期,通过Last-Modified/If-Modified-SinceETag/If-None-Match实现。
// 强缓存示例 - 设置Cache-Control
app.get('/static/js/main.js', (req, res) => {
  res.setHeader('Cache-Control', 'public, max-age=31536000');
  res.sendFile('/path/to/main.js');
});

// 协商缓存示例 - 使用ETag
app.get('/api/data', (req, res) => {
  const data = getData();
  const etag = generateETag(data);
  
  if (req.headers['if-none-match'] === etag) {
    return res.status(304).end();
  }
  
  res.setHeader('ETag', etag);
  res.json(data);
});

缓存策略分类

静态资源缓存

静态资源如JS、CSS、图片等通常采用长期缓存策略:

  • 文件名带哈希值:main.a1b2c3d4.js
  • 设置长期缓存头:Cache-Control: public, max-age=31536000
<!-- 带哈希的文件名示例 -->
<script src="/static/js/main.a1b2c3d4.js"></script>
<link href="/static/css/styles.ef5g6h7i.css" rel="stylesheet">

动态API缓存

API响应缓存需要更精细的控制:

  1. 短时间缓存:Cache-Control: max-age=60
  2. 私有缓存:Cache-Control: private
  3. 禁止缓存:Cache-Control: no-store
// API缓存策略示例
app.get('/api/user/profile', (req, res) => {
  // 用户个人数据,缓存1分钟且仅限私有缓存
  res.setHeader('Cache-Control', 'private, max-age=60');
  res.json(getUserProfile(req.user.id));
});

Service Worker缓存

Service Worker提供更高级的缓存控制能力:

// Service Worker缓存策略示例
const CACHE_NAME = 'v1';
const ASSETS = [
  '/styles/main.css',
  '/scripts/app.js',
  '/images/logo.png'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(ASSETS))
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

CDN缓存配置

CDN缓存需要与源站策略配合:

  1. 边缘节点缓存时间设置
  2. 缓存键规则(忽略查询参数、请求头等)
  3. 缓存刷新机制
# Nginx CDN缓存配置示例
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
  expires 1y;
  add_header Cache-Control "public, no-transform";
  add_header X-Cache-Status $upstream_cache_status;
}

缓存更新策略

版本化文件名

通过文件内容哈希实现精确缓存更新:

// Webpack配置示例
output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js'
}

缓存清除技术

  1. 查询参数版本号:script.js?v=1.2.3
  2. 路径版本号:/v1.2.3/script.js
  3. 服务端主动清除CDN缓存

缓存策略实践案例

案例一:电商网站商品图片

location ~* \.(jpg|jpeg|png|webp)$ {
  # 长期缓存,但通过版本号更新
  expires 1y;
  add_header Cache-Control "public";
  
  # 当图片不存在时尝试从CDN回源
  try_files $uri @cdn_fallback;
}

案例二:实时数据API

app.get('/api/stock/prices', (req, res) => {
  // 实时数据,禁用缓存
  res.setHeader('Cache-Control', 'no-store, must-revalidate');
  res.setHeader('Pragma', 'no-cache');
  res.json(getRealTimeStockData());
});

缓存监控与调优

  1. 监控缓存命中率
  2. 分析用户访问模式
  3. 调整缓存时间策略
// 缓存命中率监控中间件
app.use((req, res, next) => {
  const hit = res.getHeader('X-Cache-Hit');
  statsd.increment(`cache.${hit ? 'hit' : 'miss'}`);
  next();
});

常见问题解决方案

缓存污染问题

解决方案:

  1. 使用Vary头正确处理内容协商
  2. 避免过度使用查询参数作为缓存键
# 正确处理内容协商
location /api/data {
  proxy_cache_key "$scheme$request_method$host$uri$http_accept";
  proxy_cache_valid 200 10m;
  add_header Vary "Accept";
}

移动端缓存限制

移动端特殊处理:

  1. 适当缩短缓存时间
  2. 考虑本地存储作为补充
// 移动端使用localStorage作为缓存后备
function fetchWithCache(url) {
  const cached = localStorage.getItem(`cache:${url}`);
  if (cached) {
    return Promise.resolve(JSON.parse(cached));
  }
  
  return fetch(url)
    .then(res => res.json())
    .then(data => {
      localStorage.setItem(`cache:${url}`, JSON.stringify(data));
      return data;
    });
}

高级缓存模式

缓存优先策略

// 缓存优先实现
async function cacheFirst(request) {
  const cached = await caches.match(request);
  if (cached) return cached;
  
  const response = await fetch(request);
  const cache = await caches.open('v1');
  cache.put(request, response.clone());
  return response;
}

网络优先策略

// 网络优先实现
async function networkFirst(request) {
  try {
    const response = await fetch(request);
    const cache = await caches.open('v1');
    cache.put(request, response.clone());
    return response;
  } catch (e) {
    return await caches.match(request);
  }
}

缓存安全考虑

  1. 敏感数据避免缓存
  2. 正确处理认证资源
  3. 防范缓存投毒攻击
# 敏感数据禁止缓存
location /api/account {
  add_header Cache-Control "no-store, must-revalidate";
  add_header Pragma "no-cache";
  proxy_pass http://backend;
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌