路由
Web 服务器使用请求的 路径和 HTTP 方法 来查找正确的资源,这被称为 "路由"。
在 Vafast 中,我们通过定义路由配置对象来定义路由,包括 HTTP 方法、路径和处理函数。
基本路由
定义路由(对象字面量方式)
typescript
import { Server, defineRoute, defineRoutes } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/',
handler: () => 'Hello World'
})
])
const server = new Server(routes)
export default { fetch: server.fetch }HTTP 方法
Vafast 支持所有标准的 HTTP 方法:
typescript
import { defineRoute, defineRoutes } from 'vafast'
const routes = defineRoutes([
defineRoute({ method: 'GET', path: '/users', handler: () => 'Get users' }),
defineRoute({ method: 'POST', path: '/users', handler: () => 'Create user' }),
defineRoute({ method: 'PUT', path: '/users/:id', handler: () => 'Update user' }),
defineRoute({ method: 'DELETE', path: '/users/:id', handler: () => 'Delete user' }),
defineRoute({ method: 'PATCH', path: '/users/:id', handler: () => 'Patch user' })
])路径参数
路径参数允许您捕获 URL 中的动态值:
typescript
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users/:id',
handler: ({ params }) => {
return `User ID: ${params.id}`
}
}),
defineRoute({
method: 'GET',
path: '/posts/:postId/comments/:commentId',
handler: ({ params }) => {
return `Post: ${params.postId}, Comment: ${params.commentId}`
}
})
])查询参数
查询参数通过 query 对象访问:
typescript
import { defineRoute, defineRoutes } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/search',
handler: ({ query }) => {
const { q, page = '1', limit = '10' } = query
return `Search: ${q}, Page: ${page}, Limit: ${limit}`
}
})
])请求体
POST、PUT、PATCH 请求的请求体通过 body 对象访问:
typescript
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/users',
handler: async ({ body }) => {
return `Created user: ${body.name}`
}
})
])路由匹配规则
Vafast 使用 Radix Tree 实现高效路由匹配(O(k) 时间复杂度,k 为路径段数)。
路由类型
typescript
// 静态路由
'/users'
'/api/v1/health'
// 动态参数 (:param)
'/users/:id'
'/posts/:postId/comments/:commentId'
// 通配符 (* 或 *name)
'/files/*' // 匿名通配符,params['*']
'/static/*filepath' // 命名通配符,params['filepath']优先级规则
静态路由 > 动态参数 > 通配符注册顺序不影响优先级:
typescript
const routes = defineRoutes([
// 即使先注册动态路由
defineRoute({
method: 'GET',
path: '/users/:id',
handler: ({ params }) => `User ${params.id}`
}),
// 静态路由仍然优先匹配
defineRoute({
method: 'GET',
path: '/users/admin',
handler: () => 'Admin user'
})
])
// GET /users/admin → 'Admin user' ✅ 静态优先
// GET /users/123 → 'User 123'同一位置支持不同参数名
不同路由在同一位置可以使用不同的参数名,每个路由独立返回其定义的参数名:
typescript
const routes = defineRoutes([
defineRoute({
method: 'PUT',
path: '/sessions/:id',
handler: ({ params }) => params // { id: '123' }
}),
defineRoute({
method: 'GET',
path: '/sessions/:sessionId/messages',
handler: ({ params }) => params // { sessionId: '456' }
})
])
// PUT /sessions/123 → params = { id: '123' }
// GET /sessions/456/messages → params = { sessionId: '456' }TIP
参数名冲突时会输出警告(建议保持一致),但不影响功能。
嵌套路由
Vafast 支持嵌套路由结构,使用 children 属性:
typescript
const routes = defineRoutes([
defineRoute({
path: '/api',
children: [
defineRoute({
path: '/v1',
children: [
defineRoute({
method: 'GET',
path: '/users',
handler: () => 'API v1 users'
})
]
}),
defineRoute({
path: '/v2',
children: [
defineRoute({
method: 'GET',
path: '/users',
handler: () => 'API v2 users'
})
]
})
]
})
])路由配置选项
每个路由可以配置以下选项:
typescript
import { defineRoute, defineRoutes, Type } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/protected/:id',
middleware: [authMiddleware], // 路由级中间件
schema: {
params: Type.Object({ id: Type.String() }), // 路径参数验证
query: Type.Object({ page: Type.Number() }) // 查询参数验证
},
handler: ({ params, query }) => ({ id: params.id, page: query.page })
}),
defineRoute({
method: 'POST',
path: '/users',
schema: {
body: Type.Object({ // 请求体验证
name: Type.String(),
email: Type.String({ format: 'email' })
})
},
handler: ({ body }) => ({ user: body })
})
])新框架用法说明:
- Schema 验证现在在路由级别通过
schema字段定义,而不是在createHandler中handler直接是函数,不再需要createHandler包装- 所有路由必须使用
defineRoute包装
最佳实践
1. 使用描述性路径
typescript
// ✅ 好的
path: '/users/:id/profile'
path: '/posts/:postId/comments'
// ❌ 不好的
path: '/u/:i'
path: '/p/:p/c'2. 保持路由结构清晰
使用嵌套路由组织 API:
typescript
import { defineRoute, defineRoutes } from 'vafast'
const routes = defineRoutes([
// 用户相关路由
defineRoute({
path: '/users',
children: [
defineRoute({ method: 'GET', path: '/', handler: () => 'List users' }),
defineRoute({ method: 'POST', path: '/', handler: () => 'Create user' }),
defineRoute({ method: 'GET', path: '/:id', handler: ({ params }) => `User ${params.id}` })
]
}),
// 文章相关路由
defineRoute({
path: '/posts',
children: [
defineRoute({ method: 'GET', path: '/', handler: () => 'List posts' }),
defineRoute({ method: 'POST', path: '/', handler: () => 'Create post' })
]
})
])新框架用法说明:
- 嵌套路由中,所有子路由也必须使用
defineRoute包装- 不再支持直接使用对象字面量,必须使用
defineRoute函数
3. 使用适当的 HTTP 方法
typescript
import { defineRoute, defineRoutes } from 'vafast'
const routes = defineRoutes([
defineRoute({ method: 'GET', path: '/users', handler: () => 'Get users' }), // 获取数据
defineRoute({ method: 'POST', path: '/users', handler: () => 'Create user' }), // 创建数据
defineRoute({ method: 'PUT', path: '/users/:id', handler: () => 'Update user' }), // 完全更新
defineRoute({ method: 'PATCH', path: '/users/:id', handler: () => 'Patch user' }), // 部分更新
defineRoute({ method: 'DELETE', path: '/users/:id', handler: () => null }) // 删除(返回 204)
])4. 类型安全的路由定义
defineRoutes() 自动保留字面量类型,支持端到端类型推断:
typescript
import { defineRoute, defineRoutes, Type } from 'vafast'
import type { InferEden } from 'vafast-api-client'
// 定义并处理路由
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users/:id',
schema: { params: Type.Object({ id: Type.String() }) },
handler: ({ params }) => ({ userId: params.id })
}),
defineRoute({
method: 'POST',
path: '/users',
schema: { body: Type.Object({ name: Type.String() }) },
handler: ({ body }) => ({ name: body.name })
})
])
// ✅ 类型推断自动工作,无需 as const!
type Api = InferEden<typeof routes>新框架用法说明:
- Schema 验证移到路由配置的
schema字段- Handler 函数直接定义,自动获得类型推断
defineRoutes()使用const T泛型,自动保留字面量类型
5. 使用扩展字段
Vafast 支持在路由定义中添加任意扩展字段,用于 Webhook、权限、计费等场景:
typescript
import { defineRoute, defineRoutes, getRouteRegistry, defineMiddleware } from 'vafast'
// 计费中间件
const billingMiddleware = defineMiddleware(async (req, next) => {
const registry = getRouteRegistry()
const route = registry.get(req.method, new URL(req.url).pathname)
if (route?.billing) {
await chargeUser(req, route.billing)
}
return next()
})
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/ai/generate',
name: 'AI 生成',
// ✨ 扩展字段:计费配置
billing: { price: 0.01, currency: 'USD', unit: 'request' },
// ✨ 扩展字段:Webhook 事件
webhook: { eventKey: 'ai.generate' },
// ✨ 扩展字段:权限要求
permission: 'ai.generate',
middleware: [billingMiddleware],
handler: async ({ body }) => {
return await generateAI(body.prompt)
}
})
])更多详情请查看 路由指南 - 扩展字段。