HTTP缓存从强缓存到协商缓存,前端性能优化第一步

页面加载慢,第一反应是优化代码、压缩资源。但还有一个更容易忽略的点------HTTP缓存。

配置得当的话,二次访问几乎不用发请求,资源直接从本地拿。今天把HTTP缓存的完整机制讲清楚。

强缓存:直接从本地拿,不问服务器

强缓存的意思是:浏览器第一次请求资源后,服务器会告诉浏览器"这个资源你可以缓存多久"。在这个时间内,浏览器再次需要这个资源时,直接从本地读取,不发任何请求。

控制强缓存的两个HTTP头:

HTTP头 出现版本 优先级 说明
Cache-Control HTTP/1.1 高 max-age=3600表示缓存3600秒
Expires HTTP/1.0 低 绝对时间,如Wed, 21 Oct 2026 07:28:00 GMT

两个都存在时,Cache-Control优先。

yaml 复制代码
HTTP/1.1 200 OK
Cache-Control: max-age=31536000
Expires: Thu, 10 Oct 2027 00:00:00 GMT
Content-Type: application/javascript

// JS文件内容...

常见的Cache-Control指令:

csharp 复制代码
max-age=3600        # 缓存3600秒
no-cache            # 不用强缓存,每次都走协商缓存
no-store            # 完全不缓存
public              # 中间代理(CDN)也可以缓存
private             # 只有浏览器可以缓存,CDN不行

协商缓存:缓存过期了,问一嘴服务器

强缓存过期后,浏览器不会直接重新下载,而是先问服务器:"这个资源有没有更新?"

这就是协商缓存,通过两个请求头实现:

方案一:Last-Modified / If-Modified-Since

yaml 复制代码
# 第一次请求,服务器返回:
Last-Modified: Wed, 09 Oct 2026 12:00:00 GMT

# 缓存过期后,浏览器带上:
If-Modified-Since: Wed, 09 Oct 2026 12:00:00 GMT

# 服务器比较时间:
# 没改过 → 304 Not Modified(用本地缓存)
# 改过了 → 200 OK + 新内容

方案二:ETag / If-None-Match(推荐)

python 复制代码
# 第一次请求,服务器返回:
ETag: "abc123def456"

# 缓存过期后,浏览器带上:
If-None-Match: "abc123def456"

# 服务器比较ETag值:
# 一样 → 304 Not Modified
# 不一样 → 200 OK + 新内容 + 新ETag

ETag比Last-Modified更精确------文件内容没变但修改时间变了(比如touch了一下),Last-Modified会误判为"已更新",ETag不会。

完整的缓存决策流程

sql 复制代码
浏览器请求资源
    ↓
检查强缓存(Cache-Control/Expires)
    ↓
  未过期 → 直接使用本地缓存(200 from cache)
    ↓
  已过期
    ↓
发起协商缓存请求(带ETag或Last-Modified)
    ↓
  服务器返回304 → 使用本地缓存
  服务器返回200 → 下载新资源

实际项目中的缓存策略

不同类型文件的缓存策略不一样:

资源类型 缓存策略 理由
HTML no-cache 入口文件,必须每次都验证
JS/CSS(带hash) max-age=31536000, immutable 文件名含hash,内容变了hash就变
JS/CSS(不带hash) no-cache 需要协商缓存确认版本
图片/字体 max-age=86400 缓存一天,平衡更新频率和性能
API响应 no-store 动态数据,不缓存

Webpack打包时给文件名加content hash是最佳实践:

javascript 复制代码
// webpack.config.js
output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js'
}

这样HTML里引用的是app.a1b2c3d4.js,内容变了hash就变,浏览器会请求新文件。旧文件可以永久缓存,不用担心用户拿到旧版本。

开发者工具看缓存

Chrome DevTools的Network面板能看到每个资源的缓存状态:

  • (disk cache) --- 从磁盘缓存读取
  • (memory cache) --- 从内存缓存读取
  • (from service worker) --- 从SW读取
  • 304 --- 协商缓存命中,服务器说"没变"

调试时可以勾选"Disable cache"来跳过缓存,方便验证。


HTTP缓存是前端性能优化成本最低、收益最高的手段之一。配好了缓存策略,二次加载时间能砍掉一大半。

建议把自己项目的Network面板打开看看,有多少请求是304,有多少是真正下载的。

相关推荐
谢亮_vipxieliang1 天前
Go net/http 标准库深入——构建生产级 HTTP 服务
http·golang·iphone
Da Da 泓1 天前
谈谈HTTP
网络·网络协议·http
花间相见1 天前
【计算基础|网络02】HTTP 原理:报文结构、方法语义与状态码
网络·网络协议·http
花间相见1 天前
【计算基础|网络01】网络模型与一次完整请求全景
后端·http
墨天梦1 天前
B15_HTTP解析与OkHttp拦截器
网络协议·http·okhttp
0+1112 天前
Linux --应用层协议HTTP
网络·网络协议·http
To_OC3 天前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
小贺儿开发3 天前
Unity 局域网遥控幻灯片展示工具 3.0
科技·http·unity·工具·ppt·通信·网页
剑锋所指,所向披靡!4 天前
HTTP服务器的基本相关概念
服务器·网络协议·http