課程第 08 章 — 防刷與額度
生圖一次燒 70-180 秒的真實算力,免費開放就一定有人刷。 這頁把完整版 Worker 的配額邏輯搬到前端「模擬」一遍 —— 按下生成,親眼看一次請求怎麼被扣額、上鎖、失敗退款、最後撞上 429。 全程不打真 Worker,刷再多次也不花任何人的錢。
按「生成桌布」開始 —— 流程的每一步都會印在這裡。
一個 /image 請求要連過四關才碰得到生圖服務。每一層擋的東西不同,缺一不可。
每次請求帶一個一次性 token,Worker 向 Cloudflare 驗真假。使用者多半無感,不用點紅綠燈。
擋住:純腳本批量請求(沒有真瀏覽器就拿不到 token)
以「台北日 + IP + 種類」記一筆計數,超過就回 429 和重置時間。數字放 Worker 環境變數,可隨時調。
擋住:單一來源重度使用(就算是真人,免費額度也有上限)
生圖要跑一到三分鐘,期間同 IP 再送就回 409。鎖設 900 秒自動過期,卡住也會自己解開。
擋住:並發轟炸(開十個分頁同時按生成,只有一個進得去)
額度先扣再呼叫上游 —— 如果先跑再扣,請求還在路上時額度看起來沒少,並發就能繞過上限。確定失敗(上游回錯、逾時)由 Worker 退還,退款有冪等保護,同一件失敗退兩次也只還一次。
擋住:扣款時間差攻擊;同時對真實失敗保持公平
INSERT ... ON CONFLICT DO UPDATE SET count = count + 1 WHERE count < 上限 RETURNING count,
「讀、判斷、寫」變成資料庫裡的一步原子操作,沒有 row 回來就是超限。
-- 完整版 Worker 的扣額 SQL(D1,原子的先扣後跑)
INSERT INTO quota_counts (day, ip, kind, count) VALUES (?, ?, ?, 1)
ON CONFLICT(day, ip, kind) DO UPDATE SET count = count + 1
WHERE count < ? -- 超限時 UPDATE 不發生,RETURNING 無 row → 回 429
RETURNING count;