ByteNoteByteNote

字节笔记本

2026年5月3日

TanStack Start - Server Functions 服务端函数

API中转
¥120

TanStack Start 的服务端函数让你定义仅在服务端运行的逻辑,可以从应用的任何地方调用,保持类型安全。

什么是 Server Functions

服务端函数让你定义仅在服务端运行的逻辑,可以从应用的任何地方调用 - loaders、组件、hooks 或其他服务端函数。它们在服务端运行,但可以从客户端代码无缝调用。

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

export const getServerTime = createServerFn().handler(async () => {
  // 仅在服务端运行
  return new Date().toISOString()
})

// 从任何地方调用 - 组件、loaders、hooks 等
const time = await getServerTime()

服务端函数提供服务端能力(数据库访问、环境变量、文件系统),同时跨网络边界保持类型安全。

基础用法

服务端函数使用 createServerFn() 创建,可以指定 HTTP 方法:

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

// GET 请求(默认)
export const getData = createServerFn().handler(async () => {
  return { message: 'Hello from server!' }
})

// POST 请求
export const saveData = createServerFn({ method: 'POST' }).handler(async () => {
  return { success: true }
})

在哪里调用 Server Functions

可以从以下位置调用服务端函数:

  • Route loaders - 数据获取的最佳选择
  • Components - 使用 useServerFn() hook
  • Other server functions - 组合服务端逻辑
  • Event handlers - 处理表单提交、点击等
tsx
// 在路由 loader 中
export const Route = createFileRoute('/posts')({
  loader: () => getPosts(),
})

// 在组件中
function PostList() {
  const getPosts = useServerFn(getServerPosts)

  const { data } = useQuery({
    queryKey: ['posts'],
    queryFn: () => getPosts(),
  })
}

文件组织

对于大型应用,建议将服务端代码组织到独立文件中:

text
src/utils/
├── users.functions.ts   # Server function 包装器 (createServerFn)
├── users.server.ts      # 仅服务端助手 (DB 查询、内部逻辑)
└── schemas.ts           # 共享验证模式 (客户端安全)

文件类型说明

后缀用途导入位置
.functions.ts导出 createServerFn 包装器任何地方安全
.server.ts仅服务端代码仅在服务端函数 handler 内
.ts (无后缀)客户端安全代码(类型、模式、常量)任何地方

静态导入是安全的

服务端函数可以在任何文件中静态导入,包括客户端组件:

tsx
import { getUser } from '~/utils/users.functions'

function UserProfile({ id }) {
  const { data } = useQuery({
    queryKey: ['user', id],
    queryFn: () => getUser({ data: { id } }),
  })
}

构建过程将服务端函数实现替换为客户端 bundle 中的 RPC 存根。实际服务端代码永远不会到达浏览器。

参数与验证

服务端函数接受单个 data 参数。由于跨网络边界,验证确保类型安全和运行时正确性。

基础参数

tsx
export const greetUser = createServerFn({ method: 'GET' })
  .inputValidator((data: { name: string }) => data)
  .handler(async ({ data }) => {
    return `Hello, ${data.name}!`
  })

await greetUser({ data: { name: 'John' } })

使用 Zod 验证

tsx
import { z } from 'zod'

const UserSchema = z.object({
  name: z.string().min(1),
  age: z.number().min(0),
})

export const createUser = createServerFn({ method: 'POST' })
  .inputValidator(UserSchema)
  .handler(async ({ data }) => {
    return `Created user: ${data.name}, age ${data.age}`
  })

FormData 处理

tsx
export const submitForm = createServerFn({ method: 'POST' })
  .inputValidator((data) => {
    if (!(data instanceof FormData)) {
      throw new Error('Expected FormData')
    }
    return {
      name: data.get('name')?.toString() || '',
      email: data.get('email')?.toString() || '',
    }
  })
  .handler(async ({ data }) => {
    return { success: true }
  })

错误处理与重定向

基础错误

tsx
export const riskyFunction = createServerFn().handler(async () => {
  if (Math.random() > 0.5) {
    throw new Error('Something went wrong!')
  }
  return { success: true }
})

重定向

tsx
import { redirect } from '@tanstack/react-router'

export const requireAuth = createServerFn().handler(async () => {
  const user = await getCurrentUser()
  if (!user) {
    throw redirect({ to: '/login' })
  }
  return user
})

Not Found

tsx
import { notFound } from '@tanstack/react-router'

export const getPost = createServerFn()
  .inputValidator((data: { id: string }) => data)
  .handler(async ({ data }) => {
    const post = await db.findPost(data.id)
    if (!post) {
      throw notFound()
    }
    return post
  })

高级主题

Server Context & Request Handling

tsx
import {
  getRequest,
  getRequestHeader,
  setResponseHeaders,
  setResponseStatus,
} from '@tanstack/react-start/server'

export const getCachedData = createServerFn({ method: 'GET' }).handler(
  async () => {
    const request = getRequest()
    const authHeader = getRequestHeader('Authorization')

    setResponseHeaders(
      new Headers({
        'Cache-Control': 'public, max-age=300',
        'CDN-Cache-Control': 'max-age=3600, stale-while-revalidate=600',
      }),
    )

    setResponseStatus(200)
    return fetchData()
  },
)

可用工具

工具用途
getRequest()访问完整 Request 对象
getRequestHeader(name)读取特定请求头
setResponseHeader(name, value)设置单个响应头
setResponseHeaders(headers)通过 Headers 对象设置多个响应头
setResponseStatus(code)设置 HTTP 状态码

API 速查

API用途
createServerFn()创建服务端函数
createServerFn({ method: 'POST' })指定 HTTP 方法
.inputValidator()添加输入验证
.handler()定义服务端逻辑
useServerFn()在组件中使用服务端函数
分享: