概要: TanStack Start 中的 Server Function 需要结构化的错误处理。本文涵盖 Zod 验证错误映射、跨网络边界保持类型安全的类型化错误响应、错误分组监控,以及客户端恢复模式。
引言
TanStack Start Server Function 桥接客户端与服务器。当服务器发生错误时,需要以结构化的方式将错误传递到客户端。核心挑战在于跨越网络边界维持类型安全,同时提供有用的错误信息。
类型化错误响应
为在客户端-服务器边界维持类型安全,为错误类型定义一个可辨识联合(discriminated union)。以下是如何创建一个覆盖验证、认证、资源不存在及服务器错误的类型化错误系统:
import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'
type ApiError =
| { type: 'validation'; fields: Record<string, string[]> }
| { type: 'not_found'; resource: string }
| { type: 'auth'; message: string }
| { type: 'server'; retryAfter: number }
export const updateProfileFn = createServerFn({ method: 'POST' })
.validator(z.object({
name: z.string().min(2),
email: z.string().email(),
}))
.handler(async ({ data }): Promise<{ success: true } | ApiError> => {
try {
// 更新数据库中的用户资料
await db.updateUser(data)
return { success: true }
} catch (error) {
// 返回服务器错误,提示客户端 30 秒后重试
return { type: 'server', retryAfter: 30 }
}
})
返回类型 { success: true } | ApiError 是完全类型受控的。在客户端,TypeScript 强制你处理每一种情况,从而防止生产环境中出现未处理的错误路径。
客户端错误处理
在客户端,mutation handler 检查结果是错误还是成功。使用类型收窄模式保持错误处理分支清晰可维护:
const mutation = useMutation({
mutationFn: updateProfileFn,
onSuccess: (result) => {
if ('type' in result) {
// 处理结构化错误
if (result.type === 'validation') {
// 设置字段级错误
}
if (result.type === 'auth') {
// 重定向到登录页
router.navigate({ to: '/login' })
}
return
}
// 成功处理
toast.success('Profile updated')
},
})
客户端代码针对每种错误类型提供恰当的用户体验:验证错误显示内联字段提示,认证错误重定向到登录页,服务器错误触发重试流程——全程维持完整的类型安全。
错误类型决策指南
| 错误类型 | 触发时机 | 用户影响 | 恢复方式 |
|---|---|---|---|
| Validation | 表单输入无效 | 字段级错误提示 | 修正输入 |
| Not found | 资源缺失 | 404 页面 | 导航离开 |
| Auth | 会话过期 | 重定向至登录页 | 重新认证 |
| Rate limit | 请求过于频繁 | 等待提示 | 稍后重试 |
| Server | 内部错误 | 重试提示 | 自动重试 |
结论
TanStack Start Server Function 中的类型化错误响应提供了跨网络边界的类型安全错误处理。该模式将服务器崩溃转化为可操作的客户端恢复流程。要实现全面的错误处理,结合错误边界(Error Boundaries)处理路由级错误 UI、中间件与请求生命周期(Middleware and Request Lifecycle)实现集中式错误日志记录,以及 SaaS 监控与可观测性(SaaS Monitoring and Observability)进行生产环境错误追踪与告警。