缓存配置 #
概述 #
缓存是提升网站性能的关键技术,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