HTTP缓存相关知识总结
HTTP 缓存核心目标:减少请求、降低带宽、提升响应速度、减轻服务端压力。
整体分为两大块:强制缓存、协商缓存,优先级:强制缓存 > 协商缓存。
一、整体流程总览
1.客户端发起请求,先查本地缓存
2. 强制缓存有效:不发任何网络请求,直接使用本地资源,状态码仍为 200(from disk/memory cache)
3. 强制缓存失效:客户端带上缓存标识,向服务端发起请求走协商缓存
- 资源未更新:服务端返回 304 Not Modified,客户端继续用本地缓存
- 资源已更新:服务端返回 200 + 新资源,客户端更新本地缓存
二、第一部分:强制缓存(完全不请求服务端)
依靠两个响应头控制:Cache-Control(HTTP/1.1,主流)、Expires(HTTP/1.0,兼容)
优先级:Cache-Control > Expires
1. Expires
- 格式:
Expires: 格林威治时间 - 含义:资源绝对过期时间,到达该时间则缓存失效。
- 缺点:
- 基于客户端本地时间,客户端时间不准会导致缓存判断出错
- 只支持秒级精度,现在基本作为兼容兜底
2. Cache-Control
单位:秒,相对时间,不受客户端时间影响,功能最全。
常用取值:
| 取值 | 作用 | 适用场景 |
|---|---|---|
max-age=xxx |
缓存有效时长(从首次请求开始算) | 静态资源(图片、JS、CSS、HTML) |
public |
客户端、代理服务器(Nginx/CDN)都可缓存 | 通用静态资源 |
private |
仅客户端浏览器缓存,代理不缓存 | 用户个性化资源、登录态相关页面 |
no-cache |
不走强制缓存,强制走协商缓存 | 资源更新较频繁、需要实时校验 |
no-store |
完全禁止缓存,不落地任何本地 / 代理缓存 | 支付、隐私、敏感接口 |
must-revalidate |
缓存过期后必须校验,禁止使用过期缓存 | 对数据一致性要求高的资源 |
三、第二部分:协商缓存(必须发请求,服务端校验)
强制缓存过期后触发。客户端请求头带上资源标识,服务端对比判断是否更新。 分两组标识,同时存在时,优先校验 ETag。
1. 第一组:Last-Modified / If-Modified-Since
- 首次响应:服务端返回响应头
Last-Modified: 资源最后修改时间 - 后续请求:浏览器自动带上请求头
If-Modified-Since: 上次拿到的最后修改时间 - 服务端逻辑:
- 时间一致 → 资源未变 → 返回
304 - 时间不一致 → 资源更新 → 返回
200 + 新数据
- 时间一致 → 资源未变 → 返回
缺陷:
- 精度只有秒级
- 文件内容没变、仅修改时间被改动,也会误判为更新,导致缓存失效
2. 第二组:ETag / If-None-Match(更优方案)
- 首次响应:服务端返回资源唯一指纹(哈希值)
ETag: "abc123xyz" - 后续请求:浏览器自动携带
If-None-Match: "abc123xyz" - 服务端逻辑:
- 指纹一致 → 304
- 指纹不一致 → 200 + 新资源
优势:
- 基于内容哈希,精度更高,不受修改时间影响
- 优先级高于 Last-Modified,生产环境一般两者搭配使用
四、缓存整体执行顺序
1.浏览器请求资源
2.检查本地缓存 → 解析 Cache-Control/max-age、Expires
- 未过期:强制缓存命中,直接读本地,200 (cache)
- 已过期:进入协商缓存
3.请求头带上 If-None-Match(ETag) + If-Modified-Since(Last-Modified) 发往服务端
4.服务端依次校验:先比对 ETag,ETag 一致再比对 Last-Modified
5.校验通过(资源无更新)→ 返回 304,浏览器沿用旧缓存
6.校验不通过(资源更新)→ 返回 200 + 新资源 + 新缓存头,浏览器更新本地缓存
五、易混淆字段辨析
1. no-cache vs no-store
no-cache:不是不缓存,而是不使用强制缓存,每次都要去服务端协商no-store:彻底禁用所有缓存,请求、响应都不落地,敏感接口首选
2. 304 状态码特点
- 只返回响应头,无响应体,节省带宽
- 属于协商缓存命中,不是错误码
304 不会减少请求次数,依然会发起网络请求,只是不返回实体数据;强制缓存才会真正减少请求。
六、不同角色的缓存落地(Java 后端实战)
1. 静态资源缓存(前端 + Nginx 为主)
图片、JS、CSS、字体文件
# HTTP
Cache-Control: public, max-age=2592000 # 缓存30天
策略:长缓存 + 文件名加版本号 / 哈希,更新资源则改文件名,绕过旧缓存。
2. 动态接口 / 业务接口
- 不希望缓存:
Cache-Control: no-store(支付、个人信息) - 准实时、允许短缓存:
Cache-Control: no-cache(走协商缓存)
3. Nginx 配置 HTTP 缓存(线上常用)
Nginx 可作为代理缓存层,统一拦截静态资源,减轻后端服务压力。 核心配置:proxy_cache、proxy_cache_valid、etag on
4. Java 代码层面控制
Spring Boot 项目可通过响应头手动设置缓存规则:
response.setHeader("Cache-Control", "max-age=3600, public");
response.setHeader("ETag", etagValue);
也可结合 Spring Cache 做应用层本地缓存,和 HTTP 缓存分层使用。
七、面试经典问题 + 标准回答
1. 强制缓存和协商缓存区别?
- 强制缓存:不发网络请求,直接读本地,由
Cache-Control/Expires控制 - 协商缓存:必须发请求,服务端校验,由
ETag/Last-Modified控制 - 优先级:强制缓存 > 协商缓存
2. ETag 和 Last-Modified 区别?
- Last-Modified:基于文件修改时间,秒级精度,受客户端时间影响,存在误判
- ETag:基于资源内容哈希,精度高,优先被校验
- 生产环境一般两者同时开启
3. 为什么有了 Last-Modified 还要 ETag?
解决秒级精度不足、文件内容不变但修改时间变动导致的缓存失效问题。
4. no-cache 和 no-store 区别?
- no-cache:依旧缓存,但每次必须协商校验
- no-store:完全禁止缓存,数据不落地
5. 如何手动让浏览器缓存失效?
- 强制刷新(Ctrl+F5):忽略本地缓存,直接请求服务端
- 普通刷新(F5):跳过强制缓存,直接走协商缓存
- 修改资源 URL(加版本号、时间戳)
6. CDN 缓存和 HTTP 缓存关系?
CDN 属于代理节点缓存,遵循 HTTP Cache-Control 规则,public 资源会被 CDN 缓存,实现就近访问加速。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)