mirror of
https://github.com/SMNETSTUDIO/WeChat-AI.git
synced 2026-08-12 22:23:42 +08:00
7.4 KiB
7.4 KiB
Cloudflare Business 缓存适配
本项目源站(Fastify Docker)已输出 Cloudflare 友好 的缓存头。你只需在 Cloudflare Dashboard 配好 Cache Rules 与区域级开关,即可最大化边缘命中。
相关代码:
| 能力 | 位置 |
|---|---|
| HTML / OG 内存缓冲 + ETag | apps/api/src/static-pages.ts, index.ts |
| 统一 Cache-Control | apps/api/src/cache-headers.ts |
| 公开表情 CDN | GET /cdn/s/:id?v={content_hash} |
默认 API private, no-store |
apps/api/src/routes.ts onSend |
| CORS 白名单 | CORS_ORIGINS + PUBLIC_BASE_URL |
本阶段不上 R2;公开表情仍由源站 Redis blob 提供,靠边缘长缓存降压。
1. 源站响应策略(已实现)
| 路径 | Cache-Control | Cloudflare-CDN-Cache-Control | 鉴权 |
|---|---|---|---|
/ /docs |
public, max-age=300 |
max-age=3600, swr=86400 |
无 |
/app /admin |
public, max-age=60 |
max-age=3600, swr=86400 |
无(壳静态;数据走 API) |
/og.jpg |
public, max-age=86400, immutable |
max-age=604800 |
无 |
/cdn/s/:id?v= |
public, max-age=31536000, immutable |
同左 | 无;仅 public+approved+enabled |
/api/v1/auth/config |
private, no-store |
— | 无(登录方式开关需实时) |
/health |
no-store |
— | 无 |
其余 /api/v1/** |
private, no-store |
— | Cookie 会话 |
| 鉴权表情图 | private, no-store |
— | 登录 / admin |
HTML 带 ETag + Cache-Tag: html-shell;公开表情带 Cache-Tag: sticker-{id}(便于定向 Purge)。
2. DNS / SSL
- 域名 A/AAAA/CNAME 橙云代理到源站
- SSL/TLS → Full (strict)
- 源站用有效证书,或 Cloudflare Origin CA
- Always Use HTTPS = On
- 源站
.env:PUBLIC_BASE_URL=https://你的域名COOKIE_SECURE=trueLINUXDO_REDIRECT_URI=https://你的域名/api/v1/auth/callback- 可选
CORS_ORIGINS=https://你的域名(默认已含 PUBLIC_BASE_URL origin)
3. Cache Rules(按顺序创建,先匹配先生效)
路径:Caching → Cache Rules(Business 推荐用 Cache Rules,而不是旧 Page Rules)。
Rule 1 — Bypass 动态 API
- Name:
bypass-api-private - When:
starts_with(http.request.uri.path, "/api/v1/")
或方法为POST/PUT/PATCH/DELETE - Then: Cache eligibility = Bypass cache
Rule 2 — HTML 壳 Cache Everything + 忽略 Cookie
- Name:
cache-html-shells - When:
http.request.uri.path in {"/" "/app" "/docs" "/admin"} - Then:
- Eligible for cache
- Edge TTL: Respect origin(或 Override 1 hour)
- Browser TTL: Respect origin
- Cache key → Ignore query string(可选)
- Cookie handling → Ignore presence of cookies(关键:否则带
wa_session永远 MISS)
Rule 3 — OG 图
- Name:
cache-og - When:
http.request.uri.path eq "/og.jpg" - Then: Eligible for cache;Edge TTL Respect origin 或 7d;Ignore cookies
Rule 4 — 公开表情 CDN
- Name:
cache-cdn-stickers - When:
starts_with(http.request.uri.path, "/cdn/s/") - Then: Eligible for cache;Edge TTL Respect origin;Ignore cookies
- Cache key 保留 query string(
v=内容哈希)
Rule 5 — auth/config 短缓存(已移除)
/api/v1/auth/config现返回no-store(登录方式开关需实时生效,不应缓存)。Cloudflare 默认尊重源站Cache-Control,无public的响应不进共享缓存,故该路径无需任何缓存规则。
默认
未匹配规则时:尊重源站 Cache-Control;无 public 的不进共享缓存。
4. 区域级推荐(Business)
| 设置 | 建议 |
|---|---|
| HTTP/3 (QUIC) | On |
| Brotli | On |
| Tiered Cache | On |
| Early Hints | 可选(当前 HTML 内联,收益有限) |
| Auto Minify | Off(避免改 HTML 导致 ETag 与部署不一致) |
| Rocket Loader | Off |
| Polish | 可选;若开 WebP,注意 Accept 变体,或只对 /cdn/s/* 试 |
| Mirage | 可选(移动列表) |
| Cache Reserve | 可选(长尾表情) |
| Argo Smart Routing | 源站距用户远时可选 |
| WAF Managed Rules | On |
| Rate limiting | 建议:/api/v1/auth/*、try-chat、上传 POST |
| Bot Fight | 按需;勿误伤 OAuth 回调 |
5. 部署后刷新缓存
| 变更 | 做法 |
|---|---|
| 新版本 HTML(app/admin/docs/landing) | Purge by URL:/ /app /docs /admin,或 Purge by Tag:html-shell |
| 换图表情 | 无需 purge:?v={content_hash} 自动新键 |
| 下架 / 拒绝公开表情 | 源站 404;边缘可能仍 HIT 至 TTL → Purge URL 或 Tag sticker-{id} |
| 紧急全站 | Purge Everything(会短暂升高源站压力) |
API Purge 示例(可选):
# 需要 Zone ID + API Token (Cache Purge 权限)
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://你的域名/","https://你的域名/app","https://你的域名/docs","https://你的域名/admin"]}'
6. 验收 curl
HOST=https://你的域名
# HTML:第二次应 CF-Cache-Status: HIT(即使带假 cookie)
curl -sI "$HOST/" | grep -iE 'cf-cache-status|cache-control|etag|content-encoding'
curl -sI "$HOST/app" -H "Cookie: wa_session=fake" | grep -i cf-cache-status
# 公开表情
curl -sI "$HOST/cdn/s/$STICKER_ID?v=$HASH" | grep -iE 'cf-cache-status|cache-control'
curl -sI "$HOST/cdn/s/$STICKER_ID?v=$HASH" | grep -i cf-cache-status # HIT
# 私有 API
curl -sI "$HOST/api/v1/auth/me" -H "Cookie: wa_session=..." | grep -iE 'cache-control|cf-cache-status'
# 期望: private, no-store;DYNAMIC 或 BYPASS
# 压缩
curl -sI -H 'Accept-Encoding: br' "$HOST/app" | grep -i content-encoding
# 私有 / 未审表情不得公开
curl -sI "$HOST/cdn/s/$PRIVATE_ID" # 404
Dashboard → Caching → Cache Analytics 可看 HIT 率。
7. 反代注意
- 优先 CF 橙云 → 源站 443/8787,中间少一层
- 多节点负载均衡:使用仓库内
cloudflare-worker/(静态ORIGINS+ 健康检查 + 轮询),主域名绑 Worker;详见cloudflare-worker/README.md - 若 Nginx 仅 TLS 终结再反代 Node:
- 转发
Host、X-Forwarded-Proto、CF-Connecting-IP - 不要强行剥掉
Accept-Encoding导致双重压缩混乱
- 转发
- 源站健康检查:
GET /health(进程)或GET /health/ready(含 Redis,推荐给 LB) - 应用侧
PUBLIC_BASE_URL始终为主域名;源站 IP 不必暴露在后台 UI
8. 安全边界
/cdn/s/*仅visibility=public且review_status=approved且enabled- 私有 / pending / rejected → 统一 404
- 用户 JSON、admin、try-chat、OAuth callback 永不边缘共享缓存
- 广场列表含
inLibrary个性化,不做公共 CDN 缓存(升级路径:拆无个性化的 public catalog API)
9. 可选升级路径(未实现)
- 公开表情同步 R2 + 自定义域,源站只写 meta
- 拆
GET /api/v1/public/square/*无inLibrary的目录接口短缓存 - 内联 CSS/JS 拆出带 content-hash 的静态文件
- Cache Reserve + Image Resizing
详见主 README / 本文件与 docs/docker.md 交叉引用。