Framework 的 Server 層不等於 BFF

現代全端框架都已經把「server 跑邏輯」這件事包進來了。Next.js 有 API routes、server actions、RSC;Nuxt 有 Nitro server routes,可以同時扮演 SSR 渲染層和 BFF gateway;SvelteKit 有 server load functions 和 +server.ts endpoint。三個框架都夠格當輕量 BFF,這是事實,不用否認。

問題不在於「能不能做」,而在於「混進去之後,邊界是誰在管」。


框架 server 層的位置天生暧昧:它一腳踩在「幫瀏覽器聚合資料、格式化回應」,另一腳踩在「向後端服務發請求、持有憑證、碰觸有風險的業務邏輯」。這兩件事的安全需求、可觀測性需求、測試方式都不一樣。放在同一層,你很快就會有一個 Nuxt server route 或 Next server action,裡面同時做資料轉換、呼叫內部 API、還順帶 handle 了一條認證路徑,然後開始問自己:這段 token 驗證的 unit test 要怎麼寫?

我在跑 Nuxt 的專案時確實用過 Nitro server routes 同時接前端請求、轉發給後端服務,短期很省事。但當後端服務超過兩個、auth context 開始分叉,你就會發現那層 “輕量 gateway” 其實一點都不輕,只是沒有明顯邊界讓你感覺到重量。


判準其實很簡單:誰面向瀏覽器、誰面向後端、誰負責風險

面向瀏覽器的事情,framework server 做很合理:頁面所需資料聚合、response shape 轉換、簡單的 session 讀取。這些邏輯跟 UI 耦合,放在同個 codebase 有佈署和迭代優勢。

但一旦碰到「對外部服務的認證」、「服務間的信任邊界」、「獨立的 rate limiting / circuit breaker 策略」,最好還是往獨立服務丟。不是因為 Nitro 或 Next.js 跑不起來,而是這些邏輯的 change reason 和 UI 根本不同,混在一起只會讓兩邊都更難改。

獨立 BFF 多一個服務要顧,但部署單元清楚、可以各自測試、出事時 blast radius 也更小。框架 server 層最值得用的地方是靠近 UI 的聚合,不是讓它變成一個沒有邊界的 API gateway。


框架很方便,但別讓方便決定你的架構邊界。

重點整理

  • Next / Nuxt / SvelteKit 的 server 層都能跑 BFF 邏輯,但這是能力,不是授權。
  • 面向瀏覽器的資料聚合放 framework server 合理,但面向後端的風險邏輯不應該混進去。
  • 邊界模糊的代價不是今天就爆,而是六個月後沒人說得清楚「這段 auth 跑在哪」。
  • 獨立 BFF 的代價是部署複雜度,換來的是明確的責任劃分與可測試性。
  • 「框架能做」跟「應該讓框架做」是兩個問題,永遠分開問。

觀點 Sheng,內文 Claude 協助 · 列入 20260613 blog 翻新計劃,新漆未乾。