字
字节笔记本
2026年5月3日
TanStack Start - Middleware 中间件
API中转
¥120
中间件允许你自定义服务端路由和服务端函数的行为。中间件是可组合的,可以依赖于其他中间件来创建按层次顺序执行的操作链。
中间件用途
- 认证: 在执行服务端函数前验证用户身份
- 授权: 检查用户是否有必要权限执行服务端函数
- 日志记录: 记录请求、响应和错误
- CSP: 配置内容安全策略和其他安全措施
- 可观测性: 收集指标、跟踪和日志
- 提供上下文: 将数据附加到请求对象供其他中间件或服务端函数使用
中间件类型
| 类型 | 范围 | 方法 |
|---|---|---|
| 请求中间件 | 所有服务端请求 | .server() |
| 服务端函数中间件 | 仅服务端函数 | .client(), .server() |
请求中间件不能依赖服务端函数中间件,但服务端函数中间件可以依赖请求中间件。
中间件组合
tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
const authMiddleware = createMiddleware()
.middleware([loggingMiddleware])
.server(() => {
//...
})推进中间件链
中间件是可传递的(next-able),必须在 .server 方法中调用 next 函数来执行链中的下一个中间件:
tsx
const loggingMiddleware = createMiddleware().server(async ({ next }) => {
const result = await next() // 执行链中的下一个中间件
return result
})请求中间件
tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(
({ next, context, request }) => {
return next()
},
)与服务端路由使用
tsx
export const Route = createFileRoute('/foo')({
server: {
middleware: [loggingMiddleware],
handlers: {
GET: () => { /*...*/ },
POST: () => { /*...*/ },
},
},
})服务端函数中间件
服务端函数中间件是请求中间件的子集,具有额外功能如输入验证和客户端逻辑:
tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware({ type: 'function' })
.client(() => {
// 客户端逻辑
})
.server(() => {
// 服务端逻辑
})可用方法
| 方法 | 用途 |
|---|---|
middleware | 将中间件添加到链中 |
inputValidator | 在传递数据前修改和验证 |
client | 定义客户端逻辑 |
server | 定义服务端逻辑 |
.inputValidator 方法
tsx
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const mySchema = z.object({
workspaceId: z.string(),
})
const workspaceMiddleware = createMiddleware({ type: 'function' })
.inputValidator(zodValidator(mySchema))
.server(({ next, data }) => {
console.log('Workspace ID:', data.workspaceId)
return next()
})上下文管理
通过 next 提供上下文
tsx
const awesomeMiddleware = createMiddleware({ type: 'function' }).server(
({ next }) => {
return next({
context: {
isAwesome: Math.random() > 0.5,
},
})
},
)
const loggingMiddleware = createMiddleware({ type: 'function' })
.middleware([awesomeMiddleware])
.server(async ({ next, context }) => {
console.log('Is awesome?', context.isAwesome)
return next()
})发送客户端上下文到服务端
客户端上下文默认不发送到服务端。如需发送,必须使用 sendContext 属性:
tsx
const requestLogger = createMiddleware({ type: 'function' })
.client(async ({ next, context }) => {
return next({
sendContext: {
workspaceId: context.workspaceId,
},
})
})
.server(async ({ next, data, context }) => {
console.log('Workspace ID:', context.workspaceId)
return next()
})全局中间件
tsx
// src/start.ts
import { createStart } from '@tanstack/react-start'
const myGlobalMiddleware = createMiddleware().server(() => {
//...
})
export const startInstance = createStart(() => {
return {
requestMiddleware: [myGlobalMiddleware],
}
})实际应用示例
认证中间件
tsx
export const authMiddleware = createMiddleware({ type: 'function' })
.server(async ({ next, context }) => {
const token = getRequestHeader('Authorization')
if (!token) {
throw redirect({ to: '/login' })
}
const user = await verifyToken(token)
return next({
context: { user },
})
})日志中间件
tsx
export const loggingMiddleware = createMiddleware({ type: 'function' })
.client(async ({ next }) => {
console.log('[CLIENT] Sending request...')
const start = Date.now()
const result = await next()
console.log(`[CLIENT] Response received in ${Date.now() - start}ms`)
return result
})
.server(async ({ next }) => {
console.log('[SERVER] Processing request...')
const start = Date.now()
const result = await next()
console.log(`[SERVER] Request processed in ${Date.now() - start}ms`)
return result
})API 速查
| API | 类型 | 用途 |
|---|---|---|
createMiddleware() | 通用 | 创建中间件 |
createMiddleware({ type: 'request' }) | 请求 | 创建请求中间件 |
createMiddleware({ type: 'function' }) | 函数 | 创建服务端函数中间件 |
.middleware([m]) | 通用 | 添加依赖中间件 |
.server(fn) | 通用 | 定义服务端逻辑 |
.client(fn) | 函数 | 定义客户端逻辑 |
.inputValidator(v) | 函数 | 验证输入数据 |
上下文传递
| 方向 | 方法 | 属性 |
|---|---|---|
| 服务端 → 服务端 | next({ context }) | context |
| 客户端 → 服务端 | next({ sendContext }) | sendContext |
| 服务端 → 客户端 | next({ sendContext }) | sendContext / result.context |
分享: