← [ BACK_TO_NOTES ]

Next.js Route Handler、BFF 与 Webhook

Next.js Route Handler 可作为 Web-facing BFF 和 Webhook 接收入口,为浏览器或外部系统提供协议转换、数据聚合、鉴权、缓存失效与代理能力,同时不替代真正的 Domain Backend。

#synthesis #growing #architecture #react

[!info] related notes

  • 所属 MOC:
  • 相关概念:
  • 易混淆概念:
  • 相关资源:

Next.js Route Handler、BFF 与 Webhook

覆盖范围

这篇笔记解释 Next.js Route Handler 在两类真实系统边界中的位置:

Browser / Web Client
→ Next.js BFF
→ Domain Backend

以及:

Third-party Service
→ Webhook
→ Next.js Route Handler
→ Application / Cache / Domain Service

重点不是重新定义 BFF 或 Webhook,而是说明 route.ts 如何成为 Next.js 中的 Web-facing HTTP Adapter。

Route Handler 作为 BFF

Next.js 可以位于浏览器与后端服务之间:

Browser
   ↓
Next.js Route Handler
   ↓
Go / Java / Python Domain Service
   ↓
DB / Agent Runtime

这时 Route Handler 的价值可能包括:

  • 统一 Web Origin
  • cookie/session 到后端 token 的转换
  • 浏览器专用 DTO
  • 聚合多个服务
  • 隐藏内部服务拓扑
  • Web 特有的 rate limit / audit / headers
  • 简化前端调用数量
  • 对接 Next.js Cache / Revalidation

这属于 Backend For Frontend 的一种实现方式。

BFF 不等于 Domain Backend

不要因为 Next.js 能写 route.ts,就把独立后端的领域职责全部搬进 Web 层。

例如 BodySense:

Next.js Web / optional BFF
          ↓
Go Backend
├── session
├── event
├── permission
├── domain workflow
└── persistence boundary
          ↓
Python Agent Runtime

Next.js 更适合:

Web-facing composition / protocol adapter

而 Go 继续拥有真正的业务 authority。

因此:

Route Handler can proxy a Domain Service
≠
Route Handler becomes the Domain Service

具体 ownership 见 数据所有权与服务边界。

数据聚合

如果 Dashboard 的浏览器端需要:

Profile
Assessment
Subscription

分别来自不同服务,可以:

Browser
  ↓ GET /api/dashboard
Next.js BFF
  ├→ User Service
  ├→ Assessment Service
  └→ Billing Service
  ↓
Browser-oriented DTO

这可以减少浏览器理解后端拓扑的成本。

但聚合不是越多越好。如果 BFF 变成所有业务逻辑的唯一巨大入口,会再次形成“万能后端”。

Webhook 为什么天然属于 Route Handler

Webhook 的调用方不是你的 React UI,而是外部系统:

Stripe
CMS
GitHub
Payment Provider
External Automation

它们需要一个稳定的公开 HTTP URL:

POST /api/webhooks/stripe
POST /api/webhooks/cms

因此最自然的是:

External Service
      ↓ HTTP POST
Route Handler
      ↓
verify authenticity
      ↓
parse / validate event
      ↓
Application / Service

这也是为什么 Stripe 付款成功通知不应该首先想到 Server Action:Server Action 是 React 应用内部的 server-function mutation 边界,而 Stripe 只能通过公开 HTTP Endpoint 访问系统。

Webhook 必须验证真实性

Webhook Endpoint 是公开的,不能因为 URL 看起来很随机就相信请求。

正确模型:

HTTP Request
   ↓
verify signature / secret / timestamp
   ↓
validate event shape
   ↓
idempotency / replay handling
   ↓
execute application action

否则攻击者可能自己构造:

"payment_succeeded"
"article_published"

伪造业务事件。

因此 Webhook 安全至少要考虑:

  • 签名验证
  • 原始 body 是否参与签名
  • 时间戳 / replay 防护
  • event id 幂等
  • stable error response
  • server-side observability

Webhook 与 Cache Revalidation

上一节的 event-driven invalidation 在这里有了真实 HTTP 入口。

例如 CMS:

Editor publishes article
       ↓
CMS sends Webhook
       ↓
POST /api/webhooks/cms
       ↓
Route Handler verifies signature
       ↓
revalidateTag("articles", "max")
       ↓
Next server cache converges

所以:

External Business Event
→ HTTP Boundary
→ Cache Invalidation

它把 Next.js Tag-based Revalidation 从“一个函数调用”升级成完整系统链路。

Route Handler 代理 SSE / Streaming

BodySense 可以有两种拓扑:

A. Browser → Go SSE

或:

B. Browser → Next.js Route Handler → Go SSE

方案 B 可能带来:

  • 同源 cookie / auth
  • 隐藏后端地址
  • Web 协议转换
  • 统一错误格式
  • observability 聚合

但也增加:

  • 多一层网络 hop
  • proxy buffer / timeout 风险
  • 连接生命周期复杂度
  • 部署平台长期连接约束
  • 故障点增加

所以:

有 Route Handler
≠
所有后端请求都应该代理

只有 Web-facing boundary 真正需要 BFF 时才增加这一层。

Client Runtime 与 BFF 的常见组合

例如 TanStack Query:

Browser / TanStack Query
        ↓
/api/notifications
        ↓
Next.js Route Handler
        ↓
notificationService

例如 BodySense:

Initial page read
→ Server Component
→ Go API

Browser runtime interaction
→ Route Handler/BFF(按需)
→ Go API

Live stream
→ direct Go SSE 或 Next proxy SSE(按架构需求)

这三个路径不要求统一成一种调用方式。

BFF 的核心边界

BFF 可以:

auth adaptation
aggregation
protocol translation
UI-specific projection
web cache coordination

但不应该因为“前端方便”就绕过:

Domain authorization
transaction invariant
workflow state machine
authoritative service ownership

最短记忆

Route Handler
= Web-facing HTTP Adapter

给浏览器
→ 可以是 BFF

给第三方系统
→ 可以是 Webhook Endpoint

但:
BFF ≠ Domain Backend
Proxy ≠ 必须
Webhook ≠ 普通可信 POST
创建于 2026/9/16 更新于 2026/9/16
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本