一個沒帶 req 的 update,讓「發新文章」噴 404
客戶專案踩坑
Ricky-
08 月 22,2026

客戶用我們做的後台發一篇新文章:封面、內文圖都上傳好了,按下「發佈」,卻拿到一個乾巴巴的 404「Not Found」。最詭異的線索是——把一篇既有草稿改成「已發佈」不會出事,只有「新建即發佈」會

POST /api/posts 404 in 1.7s
  ↳ (afterChange hook) payload.update(posts, id=剛建立的文章) → NotFound
上傳 4 張圖 ✓ 各自的請求 建立文章 status=published afterChange hook.update ✗ NotFound → 404
前面每一步都成功,卡在最後 hook 回寫自己剛建立的那一列。

為什麼只有「新建」中招

我們的後台有個 afterChange hook:文章一發佈,就把它標記成「已寄送電子報」,並在背景通知訂閱者。這個 hook 裡呼叫了 payload.update() 去寫回那個標記——但沒有把 req 傳進去

在 Payload + Postgres 底下,一次寫入是包在一筆交易裡的。新建文章時,那一列還在交易裡、尚未 commit;而 hook 的 update 沒帶 req,等於另外開了一條新連線/新交易去做事。新交易看不到還沒 commit 的那一列 → 用 id 查不到 → 丟 NotFound → 一路冒到最外層變成 404。

改既有草稿時,那一列早就 commit 存在,新交易查得到,所以沒事——這也正是它躲過我們第一輪測試的原因。

沒帶 req(壞) 交易 A · 建立文章 INSERT 新列 尚未 commit 交易 B · hook.update(新連線) SELECT … WHERE id = 新列 ✗ 查不到 → 404 看不到未 commit 的列 帶 req(好) 同一筆交易 A INSERT 新列(未 commit) update(req) 走同一交易 ✓ 看得到自己剛寫的列 COMMIT ✓ → 201 已發佈
差別只在 hook 的 update 有沒有加入「本次請求的交易」。

修法只有一行

req 傳進去,讓 hook 的 update 加入同一筆交易

await payload.update({
  collection: "posts",
  id: doc.id,
  data: { newsletterSentAt: new Date().toISOString() },
  req,                       // ← 關鍵:加入本次請求的交易
  context: { skipNewsletter: true },
});

真正的教訓

  • 會寫入的 hook,要走請求本身的交易。req(或 transactionID),否則你是在跟一筆還沒 commit 的資料賽跑。
  • 這個 bug 藏得住,是測試方式害的。我們驗收時走的是「改草稿 → 發佈」(列已存在),沒測「新建即發佈」——但使用者真正走的是後者。
  • 一句話:測試要測使用者真的會走的那條路,不是最好測的那條。(這條之後單獨寫一篇。)
帶得走的一句話

框架幫你把寫入包進交易是好事;但 hook 裡再開一個寫入時,記得讓它待在同一筆交易裡。一個沒傳的 req,就足以讓「看起來一定會過」的建立流程,在最後一步查不到自己剛寫的資料。

Tags:
Payload交易Hooks


相關文章
一鍵發版背後:三個 repo 的分工
一鍵發版背後:三個 repo 的分工
ricky - 2026-07-09T02:00:00Z
一顆「發版」按鈕,背後牽動 fleet-console、部署後端與目標服務三個 repo。本文拆解版本號為什麼不能由前端計算、docker build --build-arg 如何無條件帶入 APP_...
第一個案子|什麼都不會的我,硬著頭皮成立公司
第一個案子|什麼都不會的我,硬著頭皮成立公司
ricky - 2025-05-13T13:17:28Z
當創意初現,很多人會說這想法太天馬行空、不切實際;但當同樣的點子被外國專家提出、或已有成功案例時,卻又搖身一變成了「可行方案」。這篇文章透過一張圖,揭露我們對 idea 評估方式的盲點:問題不在於技術...
別用 os 模組量容器資源
別用 os 模組量容器資源
ricky - 2026-08-21T10:42:34.774264Z
在容器裡呼叫 Node 的 os.totalmem() / os.cpus(),拿到的是宿主機的數字,不是你的容器。這篇談 namespace 與 cgroup 的差別、怎麼改用 process.cp...
訂閱電子報
隨時掌握最新的創業故事與設計開發過程
內容包含來自麒航團隊的日常分享、專業知識與工具推薦,助你了解更多創業背後的思維與技術。
麒航私房推薦
Clelereve Blog LogoClelereve Blog LogoClelereve Blog Logo
廣告區
Clelereve Blog Logo
聯絡我們
任何合作或問題請洽:
clelereve@gmail.com
Follow us
Copyright © 2025 blog.clelereve.com - All Rights Reserved
Frontend Version: -- | Backend Version: --
創業實驗筆記 - Clelereve Blog | 一個沒帶 req 的 update,讓「發新文章」噴 404 | Clelereve Blog