> 技术文档 > 服务器缓存与浏览器缓存详解_HTTP缓存控制头设置指南

服务器缓存与浏览器缓存详解_HTTP缓存控制头设置指南


服务器缓存浏览器缓存详解

一、浏览器缓存

1. 基本概念

浏览器缓存是指浏览器将请求过的资源(HTML、CSS、JS、图片等)存储在本地磁盘中,当用户再次访问相同资源时,可以直接从本地加载而无需从服务器重新请求。

2. 缓存机制

浏览器缓存主要通过HTTP响应头控制:

(1) 强缓存(无需向服务器验证)
  • Expires

    Expires: Wed, 21 Oct 2025 07:28:00 GMT
    • HTTP/1.0的规范,指定资源的绝对过期时间
    • 问题:依赖客户端时间,可能不准确
  • Cache-Control

    Cache-Control: max-age=31536000
    • HTTP/1.1的规范,优先级高于Expires
    • 常用指令:
      • max-age:缓存最大有效时间(秒)
      • no-cache:不使用强缓存,需向服务器验证
      • no-store:完全不缓存
      • public:可被任何中间节点缓存
      • private:仅浏览器可缓存
(2) 协商缓存(需向服务器验证)

当强缓存失效后,浏览器会向服务器验证资源是否修改:

  • Last-Modified/If-Modified-Since

    Last-Modified: Wed, 21 Oct 2020 07:28:00 GMTIf-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
    • 基于文件修改时间
    • 问题:1秒精度,可能文件内容未变但时间变化
  • ETag/If-None-Match

    ETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"If-None-Match: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"
    • 基于文件内容hash值,更精确
    • 优先级高于Last-Modified

3. 缓存位置

  • Memory Cache:内存缓存,快速但容量小,随进程关闭释放
  • Disk Cache:磁盘缓存,速度较慢但容量大,持久化存储
  • Service Worker Cache:PWA应用的独立缓存机制

4. 实际应用示例

<link href=\"/static/css/app.css?v=1.0.0\" rel=\"stylesheet\"><meta http-equiv=\"Cache-Control\" content=\"no-store\">

二、服务器缓存

1. 基本概念

服务器缓存是指将动态生成的内容或数据库查询结果存储在内存或高速存储中,避免重复计算或查询,提高响应速度。

2. 常见类型

(1) CDN缓存
  • 原理:将静态资源分发到全球边缘节点
  • 缓存控制
    Cache-Control: public, max-age=86400
  • 清除方式:URL变更或CDN服务商提供的刷新接口
(2) 反向代理缓存(如Nginx)
# Nginx配置示例proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m inactive=60m;server { location / { proxy_cache my_cache; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; }}
(3) 应用层缓存
  • 内存缓存:Redis/Memcached
    // Spring Cache示例@Cacheable(value = \"users\", key = \"#userId\")public User getUser(String userId) { return userRepository.findById(userId);}
  • 页面缓存:整页HTML缓存(如Varnish)
(4) 数据库缓存
  • 查询缓存:MySQL Query Cache
  • 缓冲池:InnoDB Buffer Pool

3. 缓存策略

(1) 缓存模式
  • Cache-Aside(旁路缓存):

    #mermaid-svg-ElVVjYG9liJ9LTNU {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .error-icon{fill:#552222;}#mermaid-svg-ElVVjYG9liJ9LTNU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ElVVjYG9liJ9LTNU .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ElVVjYG9liJ9LTNU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ElVVjYG9liJ9LTNU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ElVVjYG9liJ9LTNU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ElVVjYG9liJ9LTNU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ElVVjYG9liJ9LTNU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ElVVjYG9liJ9LTNU .marker.cross{stroke:#333333;}#mermaid-svg-ElVVjYG9liJ9LTNU svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ElVVjYG9liJ9LTNU .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .cluster-label text{fill:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .cluster-label span{color:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .label text,#mermaid-svg-ElVVjYG9liJ9LTNU span{fill:#333;color:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .node rect,#mermaid-svg-ElVVjYG9liJ9LTNU .node circle,#mermaid-svg-ElVVjYG9liJ9LTNU .node ellipse,#mermaid-svg-ElVVjYG9liJ9LTNU .node polygon,#mermaid-svg-ElVVjYG9liJ9LTNU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ElVVjYG9liJ9LTNU .node .label{text-align:center;}#mermaid-svg-ElVVjYG9liJ9LTNU .node.clickable{cursor:pointer;}#mermaid-svg-ElVVjYG9liJ9LTNU .arrowheadPath{fill:#333333;}#mermaid-svg-ElVVjYG9liJ9LTNU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ElVVjYG9liJ9LTNU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ElVVjYG9liJ9LTNU .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ElVVjYG9liJ9LTNU .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ElVVjYG9liJ9LTNU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ElVVjYG9liJ9LTNU .cluster text{fill:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU .cluster span{color:#333;}#mermaid-svg-ElVVjYG9liJ9LTNU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ElVVjYG9liJ9LTNU :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} 请求 缓存存在? 返回缓存 查询数据库 写入缓存 返回数据

  • Read/Write Through

    • 所有读写操作都经过缓存层
  • Write Behind

    • 先更新缓存,异步批量写入数据库
(2) 失效策略
  • TTL(Time To Live):设置固定过期时间
  • LRU(Least Recently Used):淘汰最近最少使用
  • LFU(Least Frequently Used):淘汰使用频率最低

4. 缓存问题及解决方案

问题 描述 解决方案 缓存雪崩 大量缓存同时失效 随机过期时间、多级缓存 缓存穿透 查询不存在的数据 布隆过滤器、空值缓存 缓存击穿 热点key失效 互斥锁、永不过期 数据不一致 缓存与数据库不一致 延时双删、消息队列同步

三、浏览器缓存与服务器缓存对比

特性 浏览器缓存 服务器缓存 存储位置 客户端 服务端 缓存内容 静态资源 动态内容/数据 控制方式 HTTP头 应用逻辑/CDN配置 失效机制 时间/ETag TTL/主动失效 典型应用 CSS/JS/图片 API响应/数据库查询 优势 减少网络请求 减轻服务器负载 劣势 更新不及时 架构复杂度高

四、最佳实践

1. 浏览器缓存优化

  • 静态资源:设置长期缓存(max-age=1年)+ 文件名hash
  • 动态内容no-cache或短时间缓存
  • 版本控制
    <script src=\"/app.js?v=1.0.0\"></script><script src=\"/app.1a2b3c4d.js\"></script>

2. 服务器缓存优化

  • 分层缓存:CDN → 反向代理 → 应用缓存 → 数据库缓存
  • 热点数据:预加载到内存缓存
  • 批量失效:使用消息队列异步处理
  • 监控:缓存命中率、响应时间等指标

3. 综合策略

#mermaid-svg-iN1d4PRkZ5IDOlk6 {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .error-icon{fill:#552222;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .marker.cross{stroke:#333333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .cluster-label text{fill:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .cluster-label span{color:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .label text,#mermaid-svg-iN1d4PRkZ5IDOlk6 span{fill:#333;color:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .node rect,#mermaid-svg-iN1d4PRkZ5IDOlk6 .node circle,#mermaid-svg-iN1d4PRkZ5IDOlk6 .node ellipse,#mermaid-svg-iN1d4PRkZ5IDOlk6 .node polygon,#mermaid-svg-iN1d4PRkZ5IDOlk6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .node .label{text-align:center;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .node.clickable{cursor:pointer;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .arrowheadPath{fill:#333333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .cluster text{fill:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 .cluster span{color:#333;}#mermaid-svg-iN1d4PRkZ5IDOlk6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iN1d4PRkZ5IDOlk6 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} 命中 未命中 命中 未命中 命中 未命中 命中 未命中 用户请求 浏览器缓存? 直接使用 CDN检查 返回CDN缓存 反向代理检查 返回代理缓存 应用处理 应用缓存? 返回缓存 查询数据库 写入各级缓存 返回响应

通过合理配置浏览器缓存和服务器缓存,可以显著提升Web应用性能,减少服务器负载,改善用户体验。