讲清楚说明白 - 缓存

211 阅读7分钟

web缓存体系.png

用户层

浏览器端缓存

好处

  • 减少页面加载时间
  • 减少服务器负载
  • 减少网络带宽消耗

特点

  • 浏览器是否使用缓存、缓存多久,是由服务器控制的
  • 相同 url

顺序

缓存判断顺序.png

用户操作与缓存关系

用户操作与缓存关系.webp

交互流程

  1. ​​首次请求​​:
    → 服务端返回资源及 Cache-Control: public, max-age=31536000, immutable
    → 客户端缓存资源并记录过期时间

  2. ​​二次请求​​:
    → 客户端检查当前时间是否在 max-age 有效期内
    → ​​若未过期​​:直接使用本地缓存(状态码 200 (from disk cache))
    → ​​若过期​​:触发协商缓存请求

​​ETag / If-None-Match 机制​​(优先级更高)

  • ​​服务端返回​​:ETag: "abc123"(资源唯一标识,如哈希值)

  • ​​客户端请求​​:If-None-Match: "abc123"

  • ​​服务端比对​​:
    → 若ETag匹配 → 返回 304 Not Modified(无Body,客户端复用缓存)
    → 若ETag不匹配 → 返回 200 OK + 新资源

​​Last-Modified / If-Modified-Since 机制​​

  • ​​服务端返回​​:Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT(资源最后修改时间)

  • ​​客户端请求​​:If-Modified-Since: Wed, 01 Jan 2025 00:00:00 GMT

  • ​​服务端比对​​:
    → 若资源修改时间 ≤ 客户端时间 → 304 Not Modified
    → 若资源修改时间 > 客户端时间 → 200 OK + 新资源

  • 客户端使用:If-None-Match、If-Modified-Since

  • 服务端使用:ETag、Last-Modified、Cache-Control、Expires

文件类型Webpack处理HTTP缓存策略关键说明
​​HTML入口​​index.html (无哈希)Cache-Control: no-cache, must-revalidate,ETag必须禁用缓存保证更新生效
​​JS文件​​[name].[contenthash:8].jsCache-Control: public, max-age=31536000, immutable哈希变化自动更新,强缓存1年
​​CSS文件​​[name].[contenthash:8].cssCache-Control: public, max-age=31536000, immutable同上
​​图片资源​​images/[name].[hash:8].[ext]Cache-Control: public, max-age=31536000, immutable支持WebP自动适配
​​字体文件​​fonts/[name].[hash:8].[ext]Cache-Control: public, max-age=31536000, immutable长期缓存静态资源
​​第三方资源​​单独处理Cache-Control: no-cache, must-revalidate,Last-Modified每小时检查更新

分类

强缓存
expires
  • 特点

    • http 1.0
    • 表示截止时间
    • response header 一块缓存
    • 缓存没有命中重新设定
    • 静态资源通过设置一个遥远的将来时间作为 Expires 来实现永不失效
    • 需要和 Last-modified 结合使用
  • 缺点

    • 要求服务端和客户端的时钟严格同步
    • 过期日期需要经常检查
cache-control

Cache-Control.webp

  • 特点

    • http 1.1
    • 利用客户端时间进行判断
    • 以秒为单位
  • 分类

    • max-age

      设置缓存存储的最大周期

    • public

      允许所有服务器缓存该资源

    • private

      • 该资源仅仅属于发出请求的最终用户
      • 禁止中间服务器(如代理服务器)缓存此类资源
      • 包含用户个人信息的文件
    • no-cache

      每次使用缓存资源前都必须重新验证其有效性

    • no-store

      禁止缓存

    • must-revalidate

      一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求

    • s-maxage

      • 覆盖 max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它
      • CDN 缓存
  • 缓存静态资源

    Cache-Control:public, max-age=31536000

  • 需要重新验证

    • Cache-Control: no-cache
    • Cache-Control: max-age=0, must-revalidate
  • Cache-Control: max-age=0

    如果服务器关闭或失去连接,下面的指令可能会造成使用缓存

  • 禁用缓存

    • http 禁用

      • Cache-Control:no-cache
      • pragma:no-cache
      • Cache-Control:max-age=0
      • 不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的请求
    • 根据 Cookie,认证信息等决定输入内容的动态请求

    • 经过 HTTPS 安全加密的请求

    • POST 请求无法被缓存

修改相关资源文件名称更新
返回的 HTTP 状态为 200
from cache
协商缓存
Last-Modified/If-Modified-Since
  • 特点

    • 根据上次修改时间判断
    • 分布式系统里多台机器间文件的Last-Modified必须保持一致
  • 缺点

    • 服务器上资源其实有变化,但是最后修改时间却没有变化的情况
    • 以秒为单位
    • 内容并没有任何变化,但 Last-Modified 却改变
    • 与代理服务器时间不一致
  • 需要和 cache-control 共同使用

Etag/If-None-Match
  • 根据一个标识判断
  • 缺点
    • 集群标识不是唯一
    • 分布式系统尽量关闭掉 ETag
  • Last-Modified 与 ETag 是可以一起使用的
发送一个请求,验证协商缓存是否命中

304

pragma no-cache

使用

  • 使用 HTML 的 Meta 标签
    • 所有缓存代理服务器都不支持
    • <meta http-equiv="Pragma" content="no-cache" />
  • 使用缓存有关的 HTTP 消息报头

建议

  • 同一个资源保证 URL 的稳定性
    • 使用公共类库
  • 给 css、js、图片等资源增加 HTTP 缓存头,并强制入口 html 不被缓存
    • Last-Modified/Etag
    • 设置一个较长的过期的时间
    • 资源增加时间戳或者更换路径
  • 减少对 Cookie 的依赖
    • 动态页面使用
  • 减少对 HTTPS 加密协议的使用
    • 通过特殊的配置,才能让资源得到缓存
  • 多用 Get 方式请求动态 Cgi
    • 涉及敏感信息提交的请求尽量使用 Get 方式请求
  • 动态 CGI 也是可以被缓存
    • 让动态脚本定期将内容改变时导出成静态文件,Web 直接访问带有 Last-Modified/Etag 的静态文件
    • 给动态脚本的响应头中添加 Cache-Control: max-age
    • 通过代码给动态脚本的响应头添加 Last-Modified/Etag 信息

本地存储

Localstorage

  • 可以将 Base64 格式编码的图片信息
  • 大小限制

iframe

缓存 Ajax 请求

实时性要求不是很强的请求

manifest

  • 在移动网络下首次打开效果非常不理想
  • http 头设置会导致 manifest 无法正常更新
  • Manifest 中缓存文件一旦下载出错,后续的文件将不再下载,抛出错误事件
  • Android 系统版本众多,较低版本的浏览器对 manifest 支持不完善
  • 引用 manifest 的 html 页面本身也会被缓存
  • 页面的参数传递、manifest 的发布、回滚、下线等问题

Link prefetching

禁用缓存

  • anyAjaxObj.setRequestHeader("If-Modified-Since","0")
  • anyAjaxObj.setRequestHeader("Cache-Control","no-cache")
  • URL 后面加上一个随机数
  • URL 后面加上时间戳
  • $.ajaxSetup({cache:false})

DNS缓存

浏览器 DNS 缓存

  • firefox 默认 60s
  • DNS prefetching

应用程序DNS缓存

Java(JVM)、PHP 语言本身 DNS 缓存

操作系统DNS缓存

客户端操作系统 DNS 缓存

DNS缓存服务器

  • 专用 DNS 缓存服务器
  • LocalDNS 缓存

代理层

CDN 缓存

  • 网关缓存
  • 网关服务器后面对应着一台或多台负载均衡源服务器

反向代理缓存

基于 nginx + (Squid、Varnish、Apache Traffic Server)

web 层

解释器

Opcache 操作码缓存

web 服务器

  • Apache(mod_cache)
  • nginx(FastCGI 缓存、Proxy cache)

应用层

应用服务

  • 动态内容缓存

  • 页面的静态化

    动态页面静态化,需要专门用于静态化的 CMS

  • Local Cache

    应用本地缓存,PHP(Yac、Xcache)、Java(ehcache)

代码层面上,通过代码逻辑和缓存策略,实现对数据,页面,图片等资源的缓存

数据层

查询后的数据放到内存中进行缓存

分布式缓存

Memcache、Redis

数据库

MySQL 自身缓存、innodb 缓存、MyISAM 缓存

系统层

操作系统

CPU Cache

L1(数据缓存、指令缓存)、L2、L3

内存 Cache

内存高速缓存、Page Cache

物理层

Raid 卡

Raid Cache

  • 磁盘阵列缓存
  • Raid 卡可以控制是否适用磁盘高速缓存

磁盘

Disk Cache 磁盘高速缓存