Files
blog/blog-admin/wrangler.toml
T
zqlit ca2fb7163d perf: 开启 Workers Cache 缓存 favicon,并给动态接口兜底 no-store
背景:favicon 此前只有 Cache-Control: max-age(仅浏览器缓存),
CF 边缘不缓存 Worker 响应 → 每次请求都进 Worker → 第一句就是 KV.get。
友圈页按友链数放大,KV 读量被显著放大。

★ 关键纠错:zone 级 Cache Rules 对 Worker 响应**完全无效**。
原因是 Worker 位于 zone 缓存之前("Workers sits in front of cache"),
且 Worker 直接生成响应时不发 fetch 子请求,cache status 只能是 none/unknown。
查证 CF 官方文档后确认,正确方案是 [cache] enabled = true(Workers Cache,
2026-07 上线,需 wrangler >= 4.69)。

改动:
- wrangler.toml: 新增 [cache] enabled = true;compatibility_date 提到 2026-07-24
- package.json: wrangler ^3.99 → ^4.147,workers-types ^4 → ^5(peer 要求)
- index.ts: 抽出 dispatchRequest;新增 ensureCachePolicy 兜底
  ★ 这一步是必须的:Workers Cache 遵循 RFC 9111 含**启发式缓存**,
    没带 Cache-Control 的响应也可能被缓存。实测 /api/v2/comments 开启后
    立刻被缓存(HIT, age:29)→ 用户发的新评论看不见。
    现在白名单式兜底:已显式声明可缓存的(favicon 的 s-maxage)保留,
    其余一律补 no-store。

验证(中转机实测,已清空 zone 的无效 cache rule):
- /api/favicon      → MISS → HIT,age 递增(Worker 不再执行,KV 读归零)
- /api/v2/comments  → BYPASS ×3,cache-control: no-store
- /api/v2/conf      → BYPASS,no-store
- /api/v2/healthz   → BYPASS,no-store
2026-10-06 13:28:56 +08:00

137 lines
7.2 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name = "artalk-cf"
main = "src/index.ts"
compatibility_date = "2026-07-24"
# ---------------------------------------------------------------------------
# ★ Workers Cache —— 缓存 Worker 自己生成的响应(无需回源 fetch)
#
# 为什么必须开:Worker 位于 zone 缓存之前("Workers sits in front of cache"),
# 所以 **zone 级 Cache Rules / Page Rules 对 Worker 响应完全无效**。
# 想让 /api/favicon 这类「Worker 直接返回」的响应被边缘缓存、从而不再执行
# Worker(省 KV 读 + 省 Worker 请求),唯一正解是这个 [cache] enabled。
#
# 生效条件(缺一不可):
# 1. 这里是 fetch 处理器(scheduled 等不参与缓存)
# 2. 响应带可缓存的 Cache-Control(本项目已带 s-maxage=86400)
# 3. 只缓存 GET/HEAD;带 Set-Cookie 的响应自动绕过
# 验证:连续两次 curl -I,应依次看到 cf-cache-status: MISS → HIT
# ---------------------------------------------------------------------------
[cache]
enabled = true
# ---------------------------------------------------------------------------
# D1 (必须) 创建:npx wrangler d1 create artalk-cf
# 然后把返回的 database_id 填到下面
# ---------------------------------------------------------------------------
[[d1_databases]]
binding = "DB"
database_name = "artalk-cf"
database_id = "78140776-2bfd-439a-8b05-c3eebe5d5b47"
# ---------------------------------------------------------------------------
# KV —— RSS 订阅数据(rss-robot 合并进来;KV 与 D1 共存于同一 Worker,
# 数据沿用原 rss-robot-cf 的 namespace,零迁移)
# ---------------------------------------------------------------------------
[[kv_namespaces]]
binding = "RSS_KV"
id = "d7f86a0fb43f4450a10b786fc2635128"
# ---------------------------------------------------------------------------
# 普通变量(可以明文写在仓库里)
# SITE_DEFAULT 默认站点名(博客里 site: '优世界',必须一致)
# SITE_URL 默认站点地址,用于把相对 page_key 拼成完整 page_url
# ADMIN_NAME/EMAIL 初始管理员(首次部署后调 /api/v2/setup 初始化)
# ALLOWED_ORIGINS CORS 白名单,逗号分隔;**必须包含你博客的域名**
# ---------------------------------------------------------------------------
[vars]
SITE_DEFAULT = "优世界"
SITE_URL = "https://usj.cc"
# 站内公开 API 基址(用于把 /api/favicon 这类相对地址拼成绝对地址,友圈页在博客域名下用)
PUBLIC_API_BASE = "https://api.200181.xyz"
ADMIN_NAME = "admin"
ADMIN_EMAIL = "admin@200181.xyz"
ALLOWED_ORIGINS = "https://usj.cc,https://www.usj.cc,https://post.usj.cc,https://artalk.200181.xyz,https://api.200181.xyz,http://localhost:1313,http://127.0.0.1:1313,http://localhost:8799,http://127.0.0.1:8799"
ITEMS_PER_PAGE = "20"
PENDING_DEFAULT = "false"
# ---- RSS 订阅(rss-robot 合并进来的变量)----
# SCF_PROXY_URL 腾讯云 SCF 国内代理(scfapi.usj.cc),抓国内博客用
# FEEDS_URL 远程订阅源 JSON(回退用;KV 里已有 feeds_config,留空避免 Worker 自调用)
# FEISHU_WEBHOOK_URL 飞书机器人 webhook(可选)
SCF_PROXY_URL = "https://scfapi.usj.cc"
FEEDS_URL = ""
FEISHU_WEBHOOK_URL = ""
# 文章编辑后端(自建 editor-api 容器,Worker 只做鉴权+反代)。
# 留空 = 模块自动禁用(/api/v2/editor/* 一律 503)。令牌另走 secret,别写这里。
# writeapi.usj.cc → 国内机 119.29.215.187 的 nginx 反代 → 127.0.0.1:8017 容器
# (换机时只改这条 + 新机重跑 deploy/editor-api/bootstrap.sh,域名指向新机即可)
EDITOR_API_BASE = "https://writeapi.usj.cc"
# ⚠️ 下面两个是机密,不要写在这里,用命令写入(详见「部署清单.md」第 4 步):
# npx wrangler secret put TOKEN_SECRET
# npx wrangler secret put ADMIN_PASSWORD
# 本地开发用 .dev.vars 文件(见 .dev.vars.example)
# ---------------------------------------------------------------------------
# 邮件通知(可选)
#
# 为什么走 HTTP API 而不是 SMTP:**Cloudflare Workers 没有 TCP socket**,
# 根本连不上 SMTP 服务器。(Cloudflare 2026-04 推出的原生 Email Service
# 要 Workers Paid,本项目跑在免费版上。)
#
# 用 Resend:免费 3000 封/月(**每天上限 100 封**),本项目内置了日配额保护。
# 三个都走 secret / 环境变量:
# npx wrangler secret put RESEND_API_KEY # re_xxxxxxxx(Resend 后台创建)
# npx wrangler secret put MAIL_FROM # 形如 artalk <noreply@你的域名>
# npx wrangler secret put MAIL_ADMIN # 管理员收件邮箱;不配则不发管理员通知
#
# ⚠️ MAIL_FROM 里的域名必须先在 Resend 后台验证(加 SPF/DKIM 的 DNS 记录)。
# ⚠️ 三者任一缺失都只是「少发一类邮件」,不会影响评论提交 —— 邮件全程 try/catch。
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# R2(可选)—— 评论里插图上传用。没建这个桶就自动禁用上传功能。
# 创建:npx wrangler r2 bucket create artalk-uploads
# ---------------------------------------------------------------------------
# [[r2_buckets]]
# binding = "UPLOADS"
# bucket_name = "artalk-uploads"
# ---------------------------------------------------------------------------
# 静态资源(必须)
# public/sidebar/ = 官方管理后台(客户端用它打开 iframe:{server}/sidebar/)
# public/dist/ = 官方客户端与插件,博客若想直接从服务端引也可以用
# 来源:Artalk v2.8.7 的 artalk_ui.tar.gz(预构建,无需前端构建环境)
# ---------------------------------------------------------------------------
[assets]
directory = "public"
binding = "ASSETS"
# ---------------------------------------------------------------------------
# 自定义域名
# 200181.xyz 的 NS 就在 Cloudflare 上,所以直接绑 artalk.200181.xyz 即可——
# custom_domain = true 会让 Cloudflare 自动建 DNS 记录 + 签 SSL 证书。
#
# 对比:usj.cc 的 NS 在 DNSPod,所以它不能这么绑(绑了会破坏又拍云/EdgeOne 调度)。
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# 自定义域名
# 2026-10-03 起统一到 api.200181.xyz(评论 /api/v2/* + 订阅 /api/* 同一
# Worker),artalk.200181.xyz 已解绑废弃。usj.cc 的 NS 在 DNSPod 不能这样绑。
# ---------------------------------------------------------------------------
[[routes]]
pattern = "api.200181.xyz"
custom_domain = true
# ---------------------------------------------------------------------------
# 定时任务(合并 rss-robot 的抓取):
# 17 3 * * * 评论 GC(限流/验证码清理 + healthz 缓存刷新)
# 0 0 * * * RSS 抓取批1(offset 0,35 个源)
# 0 12 * * * RSS 抓取批2(offset 35)
# ---------------------------------------------------------------------------
[triggers]
crons = ["17 3 * * *", "0 * * * *"]
[observability]
enabled = true