答案:HTTP缓存机制
问题: 空少(前端)给飞翔官网的app.js设置了Cache-Control: max-age=86400(1天)。第二天他紧急修复了一个线上bug并重新部署,但用户反馈问题依然存在。请分析原因,并给出更好的缓存策略方案。
答案:
原因分析
星宇(运维工程师)和图妹(测试工程师)一起排查后发现,问题的根源在于浏览器缓存。
当空少设置Cache-Control: max-age=86400后,浏览器会将app.js缓存到本地,并在1天内直接从本地缓存读取,不再向服务器发起请求。即使用户第二天访问官网,浏览器发现缓存尚未过期(距离上次请求不到86400秒),就直接使用本地旧版本的app.js,导致bug修复没有生效。
# 第一次请求响应头
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: max-age=86400
Last-Modified: Mon, 09 Jun 2026 08:00:00 GMT
# 第二天浏览器直接使用本地缓存,不发请求到服务器
更好的缓存策略方案
雁姐(技术经理)召集空少和鸣哥(DevOps)讨论后,制定了以下分层缓存策略:
方案一:文件名加哈希(推荐)
在构建阶段为静态资源文件名添加内容哈希,如app.a3f7b2c.js。当代码变更时,哈希值改变,URL也随之改变,浏览器会将其视为全新资源。
<!-- 构建前 -->
<script src="/app.js"></script>
<!-- 构建后(哈希自动更新) -->
<script src="/app.a3f7b2c.js"></script>
配合长期缓存:
# Nginx配置
location ~* \.(js|css|png|jpg)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
immutable表示资源在有效期内绝对不会改变,浏览器可以放心缓存一整年。
方案二:HTML不缓存,资源长期缓存
让入口HTML文件不缓存或短期缓存,HTML中引用带哈希的资源。这样只需更新HTML就能让客户端加载新资源。
# HTML响应头:不缓存或短期缓存
Cache-Control: no-cache
# 静态资源响应头:长期缓存
Cache-Control: public, max-age=31536000
方案三:使用版本号查询参数(简单但不够优雅)
<script src="/app.js?v=2"></script>
这种方式简单,但某些CDN或代理服务器可能不会将不同查询参数视为不同缓存键,存在风险。
飞翔公司最终方案
空少采用了Webpack构建 + 文件名哈希 + Nginx长期缓存的组合方案:
// webpack.config.js
module.exports = {
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
},
};
# /etc/nginx/conf.d/feixiang.conf
server {
listen 80;
server_name www.feixiang.net;
location / {
root /var/www/feixiang;
index index.html;
add_header Cache-Control "no-cache";
}
location ~* \.[a-f0-9]{8}\.(js|css)$ {
root /var/www/feixiang;
add_header Cache-Control "public, max-age=31536000, immutable";
}
}
这样,每次部署新版本时,哈希文件名自动更新,用户必定获取最新代码;同时静态资源可以享受一年的长期缓存,大幅提升重复访问速度。