前端产物文件名带内容 hash,index.html 不带,而 Caddyfile 里没有任何 Cache-Control。
Caddy 的 file_server 不设该头,浏览器遂按启发式缓存 index.html;一旦命中缓存,
前端重新部署后用户会拿着旧 index 去请求**已从镜像里删掉的旧 chunk**,
表现为后台页面打不开,只能手动强刷恢复(本次部署风控 tab 时就遇到了)。
策略:
- /assets/*(文件名带 hash,内容变则名变)→ public, max-age=31536000, immutable
- 其余静态响应(含 SPA 回退到 index.html 的)→ no-cache,每次校验
两个容易踩的点:
1. header 必须写在 file_server **之前**。route 内按书写顺序执行,
排在 file_server 之后响应头已写出,就改不动了。
2. SPA 回退(如 /admin/worker-platform)走的是 try_files 内部重写,
用 `header /index.html` 这种按请求路径匹配的写法**匹配不上**,
因此改为「排除 /assets 与接口前缀」来覆盖文档类响应。
接口前缀显式排除,避免覆盖后端自己设置的缓存头(handle 匹配后会终止链路,
这些规则本就不会落到 /api 上,显式排除只是防止日后有人在 handle 之外加规则时被误伤)。
验证(部署前用生产同款 caddy 镜像离线做的):
- caddy validate → Valid configuration
- 临时容器跑真实 snippet,实测响应头:
/assets/foo.js -> public, max-age=31536000, immutable
/index.html -> no-cache
/admin/worker-platform -> no-cache
63 lines
2.0 KiB
Caddyfile
63 lines
2.0 KiB
Caddyfile
(order-site) {
|
|
route {
|
|
# 必须放在 handle 之前:Caddy 的 route 按书写顺序执行,而 handle 匹配后即终止链路,
|
|
# 放在后面会让**所有 API 响应都跳过压缩**(生产实测订单列表 75.9KB 明文下发,
|
|
# 客户端已发 Accept-Encoding: gzip, br)。静态文件之所以一直是压缩的,
|
|
# 是因为静态文件落在 encode 之后的 file_server。SSE 响应不会被压缩(见 encode 默认规则)。
|
|
encode zstd gzip
|
|
|
|
handle /api/* {
|
|
reverse_proxy backend:3000
|
|
}
|
|
|
|
handle /health* {
|
|
reverse_proxy backend:3000
|
|
}
|
|
|
|
handle /s/* {
|
|
reverse_proxy backend:3000
|
|
}
|
|
|
|
# 缓存策略。
|
|
#
|
|
# 位置很关键:必须写在 file_server **之前**。route 内按书写顺序执行,
|
|
# header 若排在 file_server 之后,响应头已经写出,就再也改不动了。
|
|
# (上面的 handle 匹配后会终止链路,所以这些规则不会落到 /api 等反代响应上;
|
|
# 下面仍显式排除接口前缀,避免日后有人在 handle 之外加规则时被误伤。)
|
|
#
|
|
# 背景:前端产物的文件名带内容 hash,但 index.html 不带。index.html 一旦被缓存,
|
|
# 前端重新部署后用户会拿着旧 index 去请求**已从镜像里删掉的旧 chunk**,
|
|
# 表现为后台页面打不开,只能靠手动强刷恢复(生产已遇到)。
|
|
|
|
# 带 hash 的构建产物:内容变则文件名变,可以长缓存并标记 immutable
|
|
@hashedAssets path /assets/*
|
|
header @hashedAssets Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
# 其余静态响应(含 SPA 回退到 index.html 的那些)一律每次校验
|
|
@documentResponse {
|
|
not path /assets/* /api/* /health* /s/*
|
|
}
|
|
header @documentResponse Cache-Control "no-cache"
|
|
|
|
root * /srv
|
|
try_files {path} /index.html
|
|
file_server
|
|
}
|
|
}
|
|
|
|
{$CADDY_SITE_ADDR:http://localhost} {
|
|
import order-site
|
|
}
|
|
|
|
{$WORKER_SITE_ADDR:https://worker.khhao.com} {
|
|
import order-site
|
|
}
|
|
|
|
live.khhao.com {
|
|
reverse_proxy douyu-login:8800
|
|
}
|
|
|
|
|
|
mall.khhao.com {
|
|
reverse_proxy 172.17.0.1:8090
|
|
} |