飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • HTTP 基础

    • 认识HTTP协议与应用层定位
    • HTTP消息格式与报文结构
    • HTTP请求方法与幂等性
    • HTTP状态码详解
  • 连接与缓存

    • HTTP持久连接与版本演进
    • HTTP缓存机制
  • 状态与协商

    • Cookie与Session状态管理
    • HTTP重定向与内容协商
    • HTTP条件请求与范围请求
  • 安全与加密

    • HTTP认证机制
    • HTTPS与TLS握手
  • 协议演进

    • HTTP2核心特性
    • HTTP3与QUIC
  • 架构与实战

    • HTTP代理服务器与Web缓存
    • HTTP常见攻击与防御
    • HTTP实践工具与抓包分析

HTTP缓存机制

概念引入

想象你家里有一个零食柜(缓存)。早上你想吃饼干,如果柜子里有且没过期,直接拿(缓存命中);如果过期了,你得看看包装上的生产日期,打电话问超市这批货换没换(协商缓存);如果柜子里根本没有,只能去超市买(回源)。

HTTP缓存机制就是浏览器的"零食柜"——它决定了什么时候直接用本地资源,什么时候必须向服务器重新请求。对于广州飞翔科技(www.feixiang.net)这样日活百万的网站,合理的缓存策略能节省大量带宽和服务器压力。


核心内容

为什么需要缓存?

飞翔公司官网的main.css文件大小约150KB,每天有100万用户访问。如果没有缓存:

  • 每天传输:150KB × 1,000,000 = 150GB
  • 带宽费用惊人,服务器压力巨大

启用缓存后:

  • 用户第二次访问直接从本地读取,延迟接近0ms
  • 服务器只在新版本发布时传输一次

缓存命中(Cache Hit):请求的资源在缓存中且可用,直接使用,无需回源。 缓存未命中(Cache Miss):缓存中没有该资源,或资源已失效,必须向服务器重新请求。


浏览器缓存决策流程

以空少(前端)访问飞翔官网为例:

  1. 第一次打开www.feixiang.net,浏览器没有缓存 → 回源获取style.css
  2. 第二次打开,缓存还在有效期内 → 直接读取本地,速度飞快
  3. 第三天打开,缓存过期了 → 带上"身份证"(ETag)问服务器:"文件变了吗?" → 服务器说"没变" → 返回304,继续用本地缓存

强缓存:Cache-Control

强缓存是指浏览器在缓存有效期内,完全不与服务器通信,直接使用本地缓存。

核心响应头:Cache-Control(HTTP/1.1)和Expires(HTTP/1.0,已逐渐被取代)

HTTP/1.1 200 OK
Content-Type: text/css
Cache-Control: max-age=3600    ← 缓存1小时(3600秒)

/* style.css 内容 */

Cache-Control 常用指令详解:

指令含义飞翔公司应用场景
max-age=3600缓存3600秒官网CSS/JS文件
no-store禁止任何缓存,每次都回源员工工资查询页面
no-cache可以缓存,但使用前必须验证用户个人信息页
private仅浏览器可缓存,代理不可员工OA系统页面
public浏览器和代理都可缓存官网logo、公共图片
immutable资源永不变,有效期内不验证带hash的打包JS文件
// 飞翔官网静态资源的强缓存配置
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=31536000, immutable
// 1年不验证,因为文件名包含内容哈希:app.a3f2b1c.js

鸣哥(内容运营)问:"no-cache和no-store有什么区别?" 凌叔(运维)回答:"no-store是彻底不让存;no-cache是可以存,但每次用之前必须问服务器能不能用,就像你可以把备用钥匙放邻居那,但用之前必须打电话确认。"


协商缓存:验证机制

当强缓存过期后,浏览器进入协商缓存阶段——带着缓存的"身份信息"去问服务器:"我的这份还能用吗?"

方式一:Last-Modified + If-Modified-Since

// 第一次响应
HTTP/1.1 200 OK
Last-Modified: Wed, 21 Jun 2024 07:28:00 GMT

// 后续请求(缓存过期后)
GET /style.css HTTP/1.1
Host: www.feixiang.net
If-Modified-Since: Wed, 21 Jun 2024 07:28:00 GMT

// 如果文件未修改
HTTP/1.1 304 Not Modified
// 如果文件已修改
HTTP/1.1 200 OK
Last-Modified: Thu, 22 Jun 2024 09:00:00 GMT

缺点:时间精度只能到秒;如果文件内容没变但重新生成,时间也会变。

方式二:ETag + If-None-Match(更精确)

ETag(Entity Tag):服务器为资源生成的唯一标识符,通常是文件内容的哈希值。

// 第一次响应
HTTP/1.1 200 OK
ETag: "33a64df5"    ← 像资源的"指纹"

// 后续请求
GET /style.css HTTP/1.1
Host: www.feixiang.net
If-None-Match: "33a64df5"    ← 带上指纹询问

// 如果指纹匹配(内容未变)
HTTP/1.1 304 Not Modified

// 如果指纹不匹配(内容已变)
HTTP/1.1 200 OK
ETag: "33a64df6"    ← 新指纹

翼王(架构师)推荐:"飞翔官网统一用ETag,因为Last-Modified在CDN环境下容易出问题。"


强缓存 vs 协商缓存对比

对比项强缓存协商缓存
是否发请求到服务器否是(发验证请求)
状态码200 (from memory/disk cache)¹304 Not Modified
响应体无(从缓存读)无(从缓存读)
控制头Cache-Control/ExpiresLast-Modified/ETag
速度极快(0ms网络延迟)较快(一次RTT)

¹ 强缓存命中时浏览器不会向服务器发送请求,开发者工具中显示为 200 (from memory/disk cache) 或 200 (from disk cache),这是浏览器的本地标记,并非服务器返回的真实 HTTP 状态码。

浏览器缓存 vs 代理缓存

类型位置影响范围典型代表
浏览器缓存用户本地仅当前用户Chrome磁盘缓存
代理缓存网络中间节点所有经过该代理的用户公司网关、CDN节点

飞翔公司使用了阿里云CDN。靓晴(UI设计)更新了官网配色,但雁姐(用户运营)反馈"我这边看到还是旧的"。凌叔排查发现:CDN节点缓存了旧资源,需要手动刷新CDN缓存。

// 控制代理缓存的头部
Cache-Control: public, max-age=3600    ← 代理和浏览器都可缓存
Cache-Control: private, max-age=3600   ← 仅浏览器缓存

飞翔公司官网缓存策略实战

// 飞翔官网首页HTML
HTTP/1.1 200 OK
Content-Type: text/html
Cache-Control: no-cache    ← 每次用前验证,确保看到最新版

// 飞翔官网 main.css(带内容哈希)
HTTP/1.1 200 OK
Content-Type: text/css
Cache-Control: public, max-age=31536000, immutable
ETag: "a1b2c3d4"

// 飞翔官网用户数据API
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store, private    ← 敏感数据,绝不缓存

本篇小结

  • 缓存能显著减少延迟、节省带宽,是Web性能优化的核心手段
  • 强缓存通过Cache-Control: max-age等指令控制,有效期内完全不请求服务器
  • 协商缓存在强缓存过期后触发,通过ETag + If-None-Match或Last-Modified + If-Modified-Since验证资源是否变化
  • Cache-Control: no-store彻底禁用缓存;no-cache允许缓存但必须验证;private限制仅浏览器缓存;public允许代理缓存
  • 浏览器缓存只服务当前用户,代理缓存/CDN服务所有经过该节点的用户
  • 飞翔官网策略:HTML用no-cache、静态资源用长强缓存+immutable、API用no-store

动手实践

温馨提示: 以下实践示例中涉及的域名(如 www.feixiang.net)、公司场景和接口均为虚构数据,仅用于演示协议原理,实际执行时可能不会产生文档中描述的效果。建议将命令中的域名替换为你自己可访问的真实地址进行练习。

实践:用curl观察缓存头部

# 查看飞翔官网CSS的缓存策略
curl -I https://www.feixiang.net/static/css/main.css

# 观察响应头中的 Cache-Control、ETag、Last-Modified

实践:模拟协商缓存的304响应

# 第一次请求,记录ETag
curl -I https://www.feixiang.net/static/css/main.css
# 假设返回 ETag: "abc123"

# 第二次请求,带上If-None-Match
curl -I -H 'If-None-Match: "abc123"' https://www.feixiang.net/static/css/main.css
# 如果资源未变,应返回 304 Not Modified

实践:思考题

空少(前端)给飞翔官网的app.js设置了Cache-Control: max-age=86400(1天)。第二天他紧急修复了一个线上bug并重新部署,但用户反馈问题依然存在。请分析原因,并给出更好的缓存策略方案。

实践:Chrome开发者工具观察缓存

  1. 打开Chrome,访问www.feixiang.net
  2. F12打开Network面板,勾选"Disable cache"对比两次刷新
  3. 观察Size列:from disk cache、from memory cache、具体字节数的区别
  4. 点击单个请求,查看Response Headers中的缓存相关头部

查看思考题答案

上一页
HTTP持久连接与版本演进