07. Server Functions:显式 RPC 边界

Next 有 Server Actions;TanStack Start 有 Server Functions。两者都能让客户端触发服务端逻辑,但边界设计不同。

基本形态

import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'

const createPost = createServerFn({ method: 'POST' })
  .validator(z.object({ title: z.string().min(1) }))
  .handler(async ({ data, context }) => {
    return context.db.posts.create({ title: data.title })
  })

和 Next Server Actions 的差异

维度Next Server ActionsTanStack Server Functions
输入常见 FormData / 手动 parsevalidator 显式校验并推导类型
调用模型框架 action 语义强更像 typed RPC
middleware边界较分散函数级 middleware 是核心能力
部署Next runtime/platform 适配Start runtime + adapter,例如 Cloudflare Workers

一个更完整的例子:带鉴权上下文

const requireUser = createMiddleware().server(async ({ next, context }) => {
  const user = await context.auth.getUser()
  if (!user) throw new Error('Unauthorized')
  return next({ context: { user } })
})

export const updateProfile = createServerFn({ method: 'POST' })
  .middleware([requireUser])
  .validator(z.object({ displayName: z.string().min(2) }))
  .handler(async ({ data, context }) => {
    return context.db.profile.update({
      userId: context.user.id,
      displayName: data.displayName,
    })
  })

什么时候用 Server Function?

别滥用:如果只是读公开静态数据,loader 或 HTTP cache 可能更合适。不要因为有锤子,就把每个 GET 请求殴打成 RPC。
快速判断

Server Function 最关键的价值是什么?