缓存配置 #

概述 #

缓存是提升网站性能的关键技术,Caddy 支持多种缓存策略,包括浏览器缓存控制、代理缓存等。

text
┌─────────────────────────────────────────────────────────────┐
│                    缓存层次架构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│    客户端浏览器缓存                                          │
│         ↓                                                   │
│    CDN 缓存(可选)                                          │
│         ↓                                                   │
│    Caddy 代理缓存                                            │
│         ↓                                                   │
│    后端服务器                                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

浏览器缓存 #

Cache-Control 头部 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 静态资源长期缓存
    @static {
        path *.css *.js *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2
    }
    header @static Cache-Control "public, max-age=31536000, immutable"
    
    # HTML 短期缓存
    @html path *.html
    header @html Cache-Control "public, max-age=3600, must-revalidate"
    
    # API 禁用缓存
    @api path /api/*
    header @api Cache-Control "no-store, no-cache, must-revalidate"
}

Cache-Control 指令说明 #

指令 说明 示例
public 可被任何缓存存储 public
private 只能被浏览器缓存 private
no-store 不缓存 no-store
no-cache 使用前需验证 no-cache
max-age 最大缓存时间(秒) max-age=31536000
immutable 资源永不改变 immutable
must-revalidate 过期后必须验证 must-revalidate
stale-while-revalidate 过期后异步验证 stale-while-revalidate=86400

不同资源类型的缓存策略 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 图片资源 - 长期缓存
    @images path *.png *.jpg *.jpeg *.gif *.webp *.svg *.ico
    header @images Cache-Control "public, max-age=31536000, immutable"
    
    # CSS/JS - 长期缓存(带版本号)
    @assets path *.css *.js
    header @assets Cache-Control "public, max-age=31536000, immutable"
    
    # 字体文件 - 长期缓存
    @fonts path *.woff *.woff2 *.ttf *.eot
    header @fonts Cache-Control "public, max-age=31536000, immutable"
    
    # HTML - 短期缓存
    @html path *.html
    header @html Cache-Control "public, max-age=3600, must-revalidate"
    
    # JSON/XML - 短期缓存
    @data path *.json *.xml
    header @data Cache-Control "public, max-age=300"
    
    # 动态内容 - 禁用缓存
    @dynamic path /api/* /search/*
    header @dynamic Cache-Control "no-store, no-cache, must-revalidate"
}

ETag 和 Last-Modified #

ETag(默认启用) #

Caddy 自动为静态文件生成 ETag:

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # ETag 默认启用
    # 浏览器请求时会发送 If-None-Match
    # 服务器返回 304 Not Modified
}

Last-Modified(默认启用) #

Caddy 自动使用文件修改时间:

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # Last-Modified 默认启用
    # 浏览器请求时会发送 If-Modified-Since
    # 服务器返回 304 Not Modified
}

验证缓存 #

bash
# 第一次请求
curl -I https://example.com/style.css

# 响应包含
ETag: "abc123"
Last-Modified: Mon, 01 Jan 2024 00:00:00 GMT

# 第二次请求(带验证)
curl -I -H 'If-None-Match: "abc123"' https://example.com/style.css

# 响应
HTTP/2 304 Not Modified

Expires 头部 #

基本配置 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 设置过期时间
    @static path *.css *.js *.png *.jpg
    header @static Expires "Thu, 31 Dec 2025 23:59:59 GMT"
}

相对过期时间 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 使用 Cache-Control 更推荐
    @static path *.css *.js *.png *.jpg
    header @static {
        Cache-Control "public, max-age=31536000"
    }
}

Vary 头部 #

基本配置 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    encode gzip
    
    # 根据 Accept-Encoding 区分缓存
    header Vary "Accept-Encoding"
    
    # 根据多个头部区分
    @api path /api/*
    header @api Vary "Accept-Encoding, Accept, Authorization"
}

常用 Vary 配置 #

caddyfile
example.com {
    # 压缩内容
    header Vary "Accept-Encoding"
    
    # 国际化内容
    @i18n path /i18n/*
    header @i18n Vary "Accept-Language"
    
    # API 响应
    @api path /api/*
    header @api Vary "Accept, Authorization"
    
    # 移动端适配
    @mobile path /mobile/*
    header @mobile Vary "User-Agent"
}

代理缓存控制 #

禁用代理缓存 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # 禁用所有缓存
    header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate"
    
    # 或只禁用代理缓存
    header Cache-Control "private, no-cache"
}

允许代理缓存 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # 允许代理缓存
    header Cache-Control "public, max-age=3600, s-maxage=86400"
}

s-maxage 指令 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # s-maxage: 共享缓存(CDN、代理)的最大时间
    # max-age: 浏览器缓存的最大时间
    header Cache-Control "public, max-age=3600, s-maxage=86400"
}

CDN 缓存 #

CDN 友好配置 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 静态资源
    @static path *.css *.js *.png *.jpg *.svg
    header @static {
        Cache-Control "public, max-age=31536000, immutable"
        CDN-Cache-Control "max-age=31536000"
        Surrogate-Control "max-age=31536000"
    }
}

CDN 缓存清除 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # 设置缓存标签
    header Cache-Tag "api,products"
    
    # 设置缓存键
    header Cache-Key {uri}
}

条件缓存 #

基于路径的缓存 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 可缓存路径
    @cacheable {
        path /static/* /assets/* /images/*
        not path *.php
    }
    header @cacheable Cache-Control "public, max-age=31536000"
    
    # 不可缓存路径
    @nocache {
        path /api/* /admin/* /user/*
    }
    header @nocache Cache-Control "no-store, no-cache, must-revalidate"
}

基于方法的缓存 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # GET/HEAD 可缓存
    @cacheable method GET HEAD
    header @cacheable Cache-Control "public, max-age=3600"
    
    # POST/PUT/DELETE 不缓存
    @nocache method POST PUT DELETE PATCH
    header @nocache Cache-Control "no-store"
}

基于响应状态码的缓存 #

caddyfile
example.com {
    reverse_proxy localhost:3000
    
    # 成功响应缓存
    # 注意:这需要在后端设置
}

缓存预热 #

预热脚本 #

bash
#!/bin/bash
# warm-cache.sh

# 预热静态资源
urls=(
    "https://example.com/style.css"
    "https://example.com/app.js"
    "https://example.com/logo.png"
)

for url in "${urls[@]}"; do
    curl -s -o /dev/null "$url"
    echo "Warmed: $url"
done

使用 Caddy 日志分析 #

bash
# 分析热门资源
cat /var/log/caddy/access.log | jq -r '.request.uri' | sort | uniq -c | sort -rn | head -20

缓存验证 #

测试缓存配置 #

bash
# 测试 Cache-Control
curl -I https://example.com/style.css | grep -i cache-control

# 测试 ETag
curl -I https://example.com/style.css | grep -i etag

# 测试 Last-Modified
curl -I https://example.com/style.css | grep -i last-modified

# 测试 304 响应
curl -I -H 'If-None-Match: "etag-value"' https://example.com/style.css

使用 curl 测试缓存 #

bash
# 第一次请求
curl -v https://example.com/style.css 2>&1 | grep -E "(ETag|Last-Modified|Cache-Control)"

# 使用 ETag 验证
ETAG=$(curl -s -I https://example.com/style.css | grep -i ETag | cut -d' ' -f2)
curl -I -H "If-None-Match: $ETAG" https://example.com/style.css

# 使用 Last-Modified 验证
LM=$(curl -s -I https://example.com/style.css | grep -i Last-Modified | cut -d' ' -f2-)
curl -I -H "If-Modified-Since: $LM" https://example.com/style.css

完整示例 #

静态网站缓存配置 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    encode gzip zstd
    
    # 图片 - 1年缓存
    @images path *.png *.jpg *.jpeg *.gif *.webp *.svg *.ico
    header @images {
        Cache-Control "public, max-age=31536000, immutable"
        Vary "Accept-Encoding"
    }
    
    # CSS/JS - 1年缓存
    @assets path *.css *.js
    header @assets {
        Cache-Control "public, max-age=31536000, immutable"
        Vary "Accept-Encoding"
    }
    
    # 字体 - 1年缓存
    @fonts path *.woff *.woff2 *.ttf *.eot *.otf
    header @fonts {
        Cache-Control "public, max-age=31536000, immutable"
    }
    
    # HTML - 1小时缓存
    @html path *.html /
    header @html {
        Cache-Control "public, max-age=3600, must-revalidate"
        Vary "Accept-Encoding"
    }
    
    # 禁用敏感文件缓存
    @sensitive path *.json *.xml /api/*
    header @sensitive {
        Cache-Control "no-store, no-cache, must-revalidate"
        Pragma "no-cache"
    }
    
    # 安全头部
    header {
        X-Content-Type-Options "nosniff"
    }
}

API 缓存配置 #

caddyfile
api.example.com {
    reverse_proxy localhost:3000
    
    # 公共 API - 可缓存
    @public path /api/public/* /api/products/* /api/categories/*
    header @public {
        Cache-Control "public, max-age=300, stale-while-revalidate=60"
        Vary "Accept-Encoding, Accept"
    }
    
    # 私有 API - 不缓存
    @private path /api/user/* /api/admin/* /api/auth/*
    header @private {
        Cache-Control "private, no-store, no-cache, must-revalidate"
        Pragma "no-cache"
    }
    
    # 默认 - 短期缓存
    header Cache-Control "private, max-age=60"
}

SPA 应用缓存配置 #

caddyfile
app.example.com {
    root * /var/www/app
    encode gzip zstd
    
    # 静态资源 - 长期缓存
    @assets path /assets/* *.js *.css *.png *.jpg *.svg *.woff *.woff2
    header @assets {
        Cache-Control "public, max-age=31536000, immutable"
    }
    
    # index.html - 不缓存
    @index path / /index.html
    header @index {
        Cache-Control "no-store, no-cache, must-revalidate"
    }
    
    # SPA 路由
    try_files {path} /index.html
    file_server
}

电商网站缓存配置 #

caddyfile
shop.example.com {
    root * /var/www/shop
    encode gzip zstd
    
    # 静态资源
    @static path /static/* /assets/* /images/*
    header @static Cache-Control "public, max-age=31536000, immutable"
    
    # 产品图片
    @products path /products/*.jpg /products/*.png
    header @products Cache-Control "public, max-age=86400"
    
    # 产品页面 - 短期缓存
    @productPages path /product/*
    header @productPages Cache-Control "public, max-age=60, stale-while-revalidate=300"
    
    # 购物车/结账 - 不缓存
    @nocache path /cart/* /checkout/* /account/*
    header @nocache Cache-Control "no-store, no-cache, must-revalidate"
    
    # API 代理
    handle /api/* {
        reverse_proxy localhost:3000
    }
    
    file_server
}

缓存最佳实践 #

1. 资源版本化 #

html
<!-- 使用版本号或哈希 -->
<link rel="stylesheet" href="/style.css?v=1.0.0">
<script src="/app.abc123.js"></script>

2. 合理设置缓存时间 #

资源类型 推荐缓存时间
HTML 0-1小时
CSS/JS 1年(带版本号)
图片 1年
字体 1年
API 根据业务需求

3. 使用 Vary 头部 #

caddyfile
# 压缩内容必须设置
header Vary "Accept-Encoding"

4. 缓存验证机制 #

caddyfile
# ETag 和 Last-Modified 默认启用
# 确保文件服务器正确配置
file_server

下一步 #

现在你已经掌握了缓存配置,接下来学习 压缩配置 了解如何进一步优化传输性能!

最后更新:2026-03-28