扎根AI助理 種下 2026-07-14 · 最後照顧 2026-07-14⇄ 在圖譜中查看

全域回應信封與它吃掉的檔案下載

平台所有 API 的成功回應長一個樣:{ data: ... }。這靠一個全域 interceptor 把 controller 的回傳值統一包起來——前端拆信封的邏輯寫一次就好,錯誤格式({ message, errors? })也對稱收斂。

信封刻意極簡:不塞 success: true(HTTP 狀態碼已經說了)、不塞 timestamppath(追查用 request id,別把 log 的職責搬進 body)。每個「順手加的欄位」都是永遠甩不掉的合約。

然後它吃掉了我的圖片

做筆記圖片上傳後的公開讀取端點時,回傳了檔案 stream——前端收到的卻是一坨 JSON。全域 interceptor 忠實地把檔案內容包成了 { data: <Buffer 亂碼> }

修法是 NestJS 的 StreamableFile:interceptor 檢查回傳值型別,遇到它就直接放行不包。這條規則成了平台的明文慣例:任何回傳非 JSON 的端點(下載、串流、SSE)都必須走被豁免的型別,否則就會被信封吞掉。SSE 端點同理豁免。

這類「全域魔法」的通則

全域 interceptor、全域 filter、全域 guard 都是同一種東西:看不見的合約。它們讓每個 controller 少寫十行,代價是每個新加入的人(包括未來的自己)都會撞一次「為什麼我的回傳值變形了」。我的緩解手段:

  1. 豁免規則寫進根文件,跟慣例住在一起。
  2. 疊層順序明文化——例如稽核 interceptor 必須在信封 interceptor 內側(它要讀 controller 的原始回傳值來解析操作者),這個順序一旦弄反,錯誤安靜到你不會發現。

魔法可以用,但要有名字、有文件、有順序

#踩雷#nestjs#平台

讀到這裡若有一點收穫,替這顆種子澆一次水——匿名、一人一次。