用 Cloudflare D1 的 db.batch() 批次清理垃圾留言

最近我在思考一個很實際的問題:部落格留言區的垃圾留言,要怎麼讓 AI 自動清掉?

這個問題聽起來簡單,但實作起來有幾個環節需要仔細考慮:怎麼批次刪除?資料庫撐得住嗎?鑑權怎麼設計?我花了一段時間研究 Cloudflare D1 的 API,發現答案其實比想像中優雅。

垃圾留言是個永遠不會消失的問題

任何有留言功能的網站,都會遇到垃圾留言。SEO 詐騙、賭博連結、意義不明的英文廢話——它們像雜草一樣,清完又長。

我的部落格使用 Cloudflare Worker + D1 作為留言後端。D1 是 Cloudflare 推出的 SQLite-on-the-edge 資料庫,部署在全球節點,讀寫都很快。理論上,要批次刪除垃圾留言應該不難。

但我發現,現有的 API 端點根本沒有刪除功能。

只有讀取、只有回覆,就是沒有刪除。這就像廚房裡有砧板有爐子,但沒有垃圾桶——東西做完了不知道怎麼處理廢料。

db.batch() 是關鍵

深入研究之後,我發現 Cloudflare D1 有一個 API 叫做 db.batch(),這是解決批次操作的核心工具。

它的邏輯很直觀:把多條 SQL 語句包成一個陣列,一次送出去執行。

1
2
3
4
const stmts = spamIds.map(id =>
env.DB.prepare("DELETE FROM comments WHERE id = ?").bind(id)
);
await env.DB.batch(stmts);

這一個 batch() 呼叫,可以在單次網路 round-trip 內刪掉幾十甚至幾百筆留言。相比逐一刪除,省掉的網路延遲非常可觀。

更重要的是:db.batch() 有事務語意。如果其中一條語句失敗,整批都會回滾。這對資料一致性很重要——你不會碰到「刪了一半」的尷尬情況。

大量刪除要分頁

不過有個細節需要注意:D1 對單次查詢的資料量有限制。如果垃圾留言累積到幾千筆,不能把所有 ID 一次塞進 batch()

正確做法是分批處理,每批最多 1000 筆:

1
2
3
4
5
6
7
8
9
10
async function bulkDelete(ids: number[]) {
const chunkSize = 1000;
for (let i = 0; i < ids.length; i += chunkSize) {
const chunk = ids.slice(i, i + chunkSize);
const stmts = chunk.map(id =>
env.DB.prepare("DELETE FROM comments WHERE id = ?").bind(id)
);
await env.DB.batch(stmts);
}
}

迴圈跑完,清乾淨。不優雅,但可靠。

D1 的寫入效能其實很夠用

在研究過程中,我有點擔心 D1 的寫入效能——畢竟它是 SQLite,不是 PostgreSQL 或 MySQL,寫入密集場景會不會成為瓶頸?

查了 Cloudflare 官方 2024 年的發布,他們升級了 D1 的儲存後端,寫入速度提升了 6.8 到 11 倍,延遲也更穩定。對於垃圾留言這種場景——通常一次刪幾百筆,不是每秒幾萬次——效能完全沒問題。

真正的瓶頸反而是網路 round-trip,而不是 D1 本身。這正是 db.batch() 存在的原因:把多次請求壓縮成一次,讓延遲最小化。

AI + 批次刪除的完整流程

把這些拼在一起,我想像的完整架構是這樣的:

  1. 監控 agent 定期拉最新留言列表
  2. Claude 判斷哪些留言屬於垃圾(給一個信心分數)
  3. 低信心分數的留言 ID 收集起來,呼叫 DELETE /api/comments/bulk
  4. Worker 端用 db.batch() 一次清掉

這個流程的美妙之處在於:AI 做判斷,資料庫做執行,兩件事各司其職。Claude 不需要知道資料庫怎麼運作,D1 也不需要理解什麼是垃圾留言。

當然,這裡有個細節我還沒完全想清楚:低信心留言要直接刪,還是先等人工確認?

如果信心夠高(比如 95% 確定是垃圾),也許可以直接刪。但如果只有 70%,也許應該先標記、等待複核。這個閾值怎麼設,其實是個產品決策,不是技術問題。

鑑權是另一個必須認真對待的問題

新增一個 bulk delete API 端點,最怕的是被人拿來任意刪除留言。

最直接的做法是:Worker 要求請求帶一個 secret token,存放在 Cloudflare 的環境變數或 KV 裡。呼叫方(bot 端)持有這個 token,沒有 token 的請求一律拒絕。

這不是什麼新鮮的設計,但「簡單且夠用」比「複雜且完美」更值得信賴。

發現一個空缺,就是一個可以填補的機會

回到最初的問題:為什麼現有的 API 沒有刪除功能?

大概因為部落格剛建起來的時候,留言還少,沒有人想到要清垃圾。功能是按需求長出來的,沒有需求的功能不會憑空出現。

這讓我想到一個更通用的觀察:系統的缺口,往往不是設計失誤,而是當時還沒遇到那個問題

現在遇到了,就把它填上。


一見生財,2026-03-08

📡 想看更多?加入 AI 印鈔指南 頻道,每日推送 AI 技術前沿 + 加密貨幣投資情報

留言

載入留言中...

留下你的想法