# 四问诊断报告(2026-10-06) 一次性回答四个问题:CDN 刷新、KV 配额、D1 评论对账、certimate 迁移。 --- ## 一、多吉云刷新 & 已删文章还能访问 ### 1.1 先更正我自己的话 我一开始说「多吉云那条已经是全量(`--all`)」——**这句话是错的**,实测证据如下: ``` cnb-secrets.yml:33 CDN_URL_LIST: "https://usj.cc" ``` `scripts/refresh_cdn.js` 只做一件确定性的事:把 `CDN_URL_LIST` 按逗号/换行拆开, 逐条调 `/cdn/refresh/add.json`(`rtype: "path"`)。**当前配置里这个变量只有首页一个 URL**。 结论:**多吉云确实不是全量刷新,只刷新了首页 `https://usj.cc`。** ### 1.2 那为什么删掉的文章还能访问? 不是多吉云的问题。实测这条 URL: ``` $ curl -sI https://usj.cc/202610021614.html HTTP/1.1 200 OK Server: marco/3.2 ← 又拍云特征头 X-Cache-Lookup: Hit From Upstream Cluster ← 命中缓存 Last-Modified: Sun, 04 Oct 2026 14:12:26 GMT ← 旧副本时间 Cache-Control: max-age=691200 ← 8 天 TTL Age: 131684 ← 已缓存约 1.5 天 ``` 判别实验(关键): | URL | 状态 | 说明 | |---|---|---| | `/202610021614.html`(已删除) | **200** | 缓存里还有旧副本 | | `/zzz-not-exist-111.html`(从未存在) | **302 → /404.html** | 源站没这个文件 | 两者行为不同 ⇒ 说明**源站确实已经没有这个文件了**(本地 `content/` 和 `public/` 均已确认无此页), 现在返回 200 完全是**又拍云上的 8 天旧副本**。 ### 1.3 根因:两条 CDN 线路都刷不到「已删除页」 `scripts/purge_list.js` 的逻辑是:遍历 **构建产物 `public/`**,把里面所有 `.html` 列出来提交刷新。 ```js // 全量时 walkHtml('public') —— 遍历构建产物 // 已删除的页面自然不在里面 → 永远不会被提交刷新 ``` 也就是说:**刷新清单只会包含「现在存在的页面」**。一个页面被删掉后, 它就从清单里消失了,于是 CDN 上的旧副本只能等 TTL 自然过期。 - 又拍云:HTML `max-age=691200` = **8 天** - 多吉云:只刷首页,问题更明显 ### 1.4 处置建议 | 方案 | 说明 | 成本 | |---|---|---| | **A. 什么都不做** | 等 8 天自然过期 | 0 | | **B. 手动刷新一次**(推荐) | 把已知的已删 URL 提一次刷新,立刻生效 | 一次性 | | C. 流水线加「删除清单」 | 构建时对比上一次产物,把消失的 `.html` 追加进 purge 清单 | 改脚本 | 对已删文章这种低频事件,**B 足够**。需要的话我可以立刻把已知的那几个已删 URL 提交到又拍云+多吉云。 --- ## 二、KV 配额告警:需要调整吗? ### 2.1 告警内容 > 已使用 Workers KV 免费套餐每日限制的 **50%**,超限将返回 429;重置时间 2026-10-06 00:00 UTC。 > 免费额度:读 100,000/天、写 1,000/天、删 1,000/天、list 1,000/天。 ### 2.2 谁在吃配额?(实测 4 类来源) | 来源 | 代码位置 | 频率 | 影响 | |---|---|---|---| | **评论数缓存** | `comments.ts:180/206` | 每次评论列表请求,miss 时写(TTL 600s) | 读 + 写 | | **评论数版本号** | `comments.ts:53/61` | 评论增删时写 | 写 | | **friend-link favicon** | `routes/rss/tools.ts:86` | **每次访问友链/友圈页,每个友链一次** | **读(大户)** | | 人机验证 / 通知节流 | `human.ts` / `admin-notify.ts` | 低 | 少量 | **读数最大的就是 favicon 接口。** 友链共 54 条(可见 42 条),其中 15 条头像走 `/api/favicon`: ```js // circles.html / linkify.js img.src = RSS_API_BASE + '/api/favicon?url=' + encodeURIComponent(target); ``` 每刷一次友圈/友链页 → 触发 N 次 `/api/favicon` → 每次至少 1 次 KV `get`。 favicon 本体有 24h 浏览器缓存,但**首访、清缓存、换设备都会重新打**。 ### 2.3 建议:**暂时不用调整,但建议做一个小优化** - **读 50% 是「接近」不是「超了」**,且每天 UTC 0 点清零。按当前站点的访问量,正常不会打穿。 - 即使打穿,后果是 `/api/favicon` 走兜底字母图、评论数退化为实时查库——**不是灾难性故障**。 - 免费版写限额 1,000/天,比读更容易被评论数缓存写穿。真正的风险点是**评论突然暴涨**或**有人刷评论**。 **可做的小优化(成本低、收益直接):** 1. favicon 接口响应已经带了 `Cache-Control: max-age=86400`,可以加一层 **Cloudflare Cache Rule**, 让 `/api/favicon*` 在边缘缓存 24h,这样 KV 读基本归零。 2. 若担心写限额,把 `cml:ver:` 的写入合并/延迟(比如 5 分钟内同页重复 bump 只写一次)。 **要不要升级到付费($5/月)?** 目前**不需要**。等到真收到「已超限」而不是「接近」的邮件再说。 --- ## 三、D1 评论对账:老文章评论为什么没了 ### 3.1 先说结论(这个和你想的不一样) 原库 **3979 条**评论 / 线上 **3423 条**。乍看差 556 条,但拆开看,**「缺失」的绝大部分根本不是评论**: | 项 | 数量 | |---|---| | 线上缺失合计 | **711 条 / 63 页** | | 其中 **点赞型记录**(内容含 `[LIKE]`) | **494 条(69%)** | | → **真实评论型缺失** | **217 条** | **关键发现:线上 `[LIKE]` 记录为 0 条。** ``` $ SELECT SUM(CASE WHEN content LIKE '%[LIKE]%' THEN 1 ELSE 0 END) FROM comments; → 0 ``` 说明当年数据导入时,**已经主动过滤掉了所有点赞型记录**——这是正确的设计(点赞不该占用评论表)。 所以拿原库和线上直接比条数,本身就会假性多出 494 条。 ### 3.2 缺失的 217 条真实评论,按站点拆 | 站 | 缺失 | 其中点赞 | 真实 | |---|---|---|---| | 伍比贰 | 521 | 431 | **90** | | 优世界 | 101 | 0 | **101** | | 演示站 | 48 | 41 | 7 | | 往后 | 41 | 22 | 19 | **注意:「伍比贰」「演示站」「往后」是另外的站点,不属于 usj.cc。** 它们的数据本来就不该进本站。 ### 3.3 「优世界」那 101 条对得上现站吗? 逐页核对,结果是 **一页都对不上**: | page_key | 条数 | 现站情况 | |---|---|---| | `/yl` | 48 | 页面不存在(是 2022 年的旧友链页) | | `/20241018-some-useful-win-tools` | 12 | 文章还在,但 slug 已改为 `20241019`,且**是草稿**(未发布) | | `/27`、`/13`、`/m/17` 等 | 41 | 不存在(旧站的分页/短链) | | `/20240921-clock-in` | 5 | 文章已删除 | **根因不是「key 对不上」,而是这些文章本身已经不存在了。** 评论是挂在「已删除文章」上的,key 再怎么规范化也接不回来。 ### 3.4 站上现存页面 vs 线上 —— 有没有真的错位? **没有。** 用现站 284 个 slug 逐一匹配线上缺失的 63 个 key: ``` 能对上现存页面: 1 页 / 4 条 (只有 /about.html) 对不上 : 62 页 / 707 条 ``` **唯一一个疑似错位:`/about.html`(4 条)**——但深挖后发现**它也不需要修**: ``` id=14229 /about.html [伍比贰] 2026-02-07 👍 已点赞 Cool [LIKE] id=14268 /about.html [伍比贰] 2026-02-12 👍 已点赞 Interesting [LIKE] id=14269 /about.html [伍比贰] 2026-02-12 👍 已点赞 很棒的文章! [LIKE] id=14276 /about.html [伍比贰] 2026-02-13 👍 已点赞 写得很好 [LIKE] ``` 这 4 条全是**点赞型记录**,而且属于**「伍比贰」站**,本就不该进本站。 → **结论:线上 D1 没有任何错位,完全不需要修复。** ### 3.5 线上「多出」的 7 页是什么? | page_key | 条数 | |---|---| | `/20260630162329.html` | 25 | | `/20260724101237.html` | 24 | | `/20211001.html` | 14 | | `/20261005113439.html` | 13 | | `/20260629223659.html` | 10 | | `/202610011226.html` | 2 | | `/20261005213010.html` | 2 | 这些是**导出 db 之后新增的评论**(2026-06 之后),属于正常增长,不用动。 ### 3.6 修复建议 **结论:线上 D1 不需要做任何修复。** 你的直觉「很多评论没跟页面 key 对应上、老文章没评论了」—— 真实情况是:**那些评论对应的文章,本身已经不在了**(已删除 / 仍是草稿 / 属于别的站), key 再怎么规范化也接不回来。线上数据是**干净的**。 **不建议做的**: - ❌ 批量把「伍比贰/演示站/往后」的评论导进来 —— 那是别的站的数据(含大量点赞记录) - ❌ 把 `/yl`、`/27` 等改成别的 key —— 没有正确的目标,改了反而污染 - ❌ 恢复 494 条点赞记录 —— 线上设计本就不存点赞(`[LIKE]` 记录当前为 0) **如果你更看重「把老评论展示出来」**,唯一的正路是**重建这些页面** (把已删文章从 git 历史恢复,或用 slug 重定向)。这个要单独评估,工作量比改 key 大得多。 **但请注意**:即使恢复了页面,能救回的也只是极小一部分—— 「优世界」站真实缺失的 101 条里,48 条属于 `/yl`(2022 年旧友链页), 41 条属于 `/27` `/13` `/m/17` 等旧站分页短链,只有 12 条是正经文章评论。 ### 3.7 那「评论少了」的体感从哪来? 很可能来自这两点(都正常): 1. **点赞不再算评论**:原库 494 条点赞在导入时被过滤,前端看到的评论数自然变少。 2. **老文章页面已删**:文章没了,评论区自然也没了。 如果确实想提升「评论数」,更实际的做法是**在新文章上做引导**,而不是抢救旧数据。 --- ## 四、certimate 能否迁到 Cloudflare ### 4.1 你现在的架构 ``` certimate(跑在某台服务器上) ├─ 申请:litessl CA,*.usj.cc + usj.cc,DNS-01,tencentcloud-dns ├─ 部署:dogecloud-cdn(多吉云 CDN) └─ 部署:1panel website(那台服务器上的站点) 定时:10 12 * * *(每天 UTC 12:10) 失败邮件:177018615@qq.com ``` 当前线上证书实测: ``` issuer = LiteSSL RSA CA 2025(TrustAsia) subject = CN=usj.cc SAN = usj.cc, *.usj.cc 有效期 = 2026-09-08 → 2026-12-07 ``` ### 4.2 certimate 支持 Cloudflare 吗? **支持,而且支持两种角色:** | 角色 | 支持 | 说明 | |---|---|---| | **DNS provider(申请用)** | ✅ | 填 Cloudflare API Token 即可,用于 DNS-01 验证 | | **Deploy provider(部署用)** | ✅ | 可将证书部署到 Cloudflare | (certimate 官方:60+ DNS 托管商、120+ 部署目标,Cloudflare 在列。) ### 4.3 你的真实目标:「把服务器干掉」 需要先厘清一件事:**usj.cc 现在到底谁在提供 HTTPS?** 从实测响应头看: ``` Server: marco/3.2 ← 又拍云 Via: T.206.M, V.403-zj-fud-202, ... ← 又拍云多级节点 ``` **对外服务的是又拍云 CDN**,不是那台服务器。那台服务器承担的是: - 跑 certimate(证书申请+分发) - 1Panel 上的 write-server / editor-api 等自建服务 所以「干掉服务器」要分清两件事: **① 只干掉「证书维护」这件事** → **完全可以,用 Cloudflare 托管 DNS + certimate 的 CF provider。** 路径: 1. 把 `usj.cc` 的 **DNS 托管迁到 Cloudflare**(当前在腾讯云 DNSPod) 2. certimate 里把「DNS 提供商」从 `tencentcloud-dns` 换成 `cloudflare`(填 CF API Token) 3. 证书申请照旧(litessl 或换 Let's Encrypt),DNS-01 走 CF API 4. 部署目标改为「Cloudflare」(如果把站点也迁到 CF)或保留又拍云/多吉云 **② 连「站点托管」也迁到 Cloudflare** → **可行但有取舍:** | 优点 | 缺点 | |---|---| | CF 免费版自带 Universal SSL(免申请免续期) | 国内访问速度**不如又拍云/多吉云**(CF 免费版节点在境外) | | 不用再管 90 天续期 | 免费版 Universal SSL 只覆盖 `example.com` + `*.example.com` | | 有 CF Origin CA(15 年有效期)给回源用 | 想用 CF 自签源站证书需另配 | ### 4.4 ⚠️ 关键提醒:国内访问速度 你的读者主要在国内。**又拍云/多吉云是国内 CDN,Cloudflare 免费版是境外节点**—— 如果为了省一台服务器而把整个站点切到 CF,**国内访问大概率变慢**(首包延迟从几十 ms 变成几百 ms)。 **所以我建议:** - ✅ **可以做的**:把 `usj.cc` 的 DNS 托管迁到 Cloudflare(CF DNS 免费、管理方便、API 完善), certimate 用它做 DNS-01,证书照旧签发后部署到**又拍云 + 多吉云**。这样证书维护不再依赖服务器上的 1Panel 部署环节。 - ⚠️ **建议保留又拍云/多吉云做 CDN**,不要为了「干掉服务器」把站点也搬到 CF。 - ❌ 如果那台服务器还跑着 write-server / editor-api,**那就不能关**——关之前先确认没有别的服务在跑。 ### 4.5 你现在到底能不能关服务器? 需要先回答这个问题:**那台服务器上除了 certimate,还跑着什么?** - 如果只有 certimate → 迁完就能关 ✅ - 如果还有 write-server / editor-api(按记忆应该有)→ **关不掉** ⚠️ 建议你在关之前先列一下那台机器上的服务清单。需要的话我可以帮你连上去盘一遍。 --- ## 附:本次用到的排查命令 ```bash # CDN 缓存判别 curl -sI https://usj.cc/202610021614.html | grep -iE "server|age|last-modified|x-cache" # D1 查询(curl 走 IPv4,Node fetch 会 ENETUNREACH) curl -s -X POST \ "https://api.cloudflare.com/client/v4/accounts/$ACC/d1/database/$DB/query" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"sql":"SELECT page_key, COUNT(*) FROM comments GROUP BY page_key"}' # 线上是否有点赞记录 # → SELECT SUM(CASE WHEN content LIKE '%[LIKE]%' THEN 1 ELSE 0 END) FROM comments; → 0 ```