ab61be4875dab8904db1918776eebb53085c2d06
- Created `https-server.md` detailing the HTTP server design, including request normalization, routing, and built-in routes. - Added `router.md` outlining the router system design, core components, and execution flow. - Introduced `ws-server.md` for the WebSocket server design, covering connection handling, message protocols, and custom listener registration.
router
一个轻量级的路由框架,支持链式调用、中间件、嵌套路由等功能。
快速开始
import { App } from '@kevisual/router';
const app = new App();
app.listen(4002);
app
.route({ path: 'demo', key: '02' })
.define(async (ctx) => {
ctx.body = '02';
})
.addTo(app);
app
.route({ path: 'demo', key: '03' })
.define(async (ctx) => {
ctx.body = '03';
})
.addTo(app);
核心概念
RouteContext 属性说明
在 route handler 中,你可以通过 ctx 访问以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
query |
object |
请求参数,会自动合并 payload |
body |
number | string | Object |
响应内容 |
code |
number |
响应状态码,默认为 200 |
message |
string |
响应消息 |
state |
any |
状态数据,可在路由间传递 |
appId |
string |
应用标识 |
currentId |
string |
当前路由ID |
currentPath |
string |
当前路由路径 |
currentKey |
string |
当前路由 key |
currentRoute |
Route |
当前 Route 实例 |
progress |
[string, string][] |
路由执行路径记录 |
nextQuery |
object |
传递给下一个路由的参数 |
end |
boolean |
是否提前结束路由执行 |
app |
QueryRouter |
路由实例引用 |
error |
any |
错误信息 |
index |
number |
当前路由执行深度 |
needSerialize |
boolean |
是否需要序列化响应数据 |
上下文方法
| 方法 | 参数 | 说明 |
|---|---|---|
ctx.call(msg, ctx?) |
{ path, key?, payload?, ... } | { id } |
调用其他路由,返回完整 context |
ctx.run(msg, ctx?) |
{ path, key?, payload? } |
调用其他路由,返回 { code, data, message } |
ctx.forward(res) |
{ code, data?, message? } |
设置响应结果 |
ctx.throw(code?, message?, tips?) |
- | 抛出自定义错误 |
完整示例
import { App } from '@kevisual/router';
import z from 'zod';
const app = new App();
app.listen(4002);
// 基本路由
app
.route({ path: 'user', key: 'info', id: 'user-info' })
.define(async (ctx) => {
// ctx.query 包含请求参数
const { id } = ctx.query;
// 使用 state 在路由间传递数据
ctx.state.orderId = '12345';
ctx.body = { id, name: '张三' };
ctx.code = 200;
})
.addTo(app);
app
.route({ path: 'order', key: 'pay', middleware: ['user-info'] })
.define(async (ctx) => {
// 可以获取前一个路由设置的 state
const { orderId } = ctx.state;
ctx.body = { orderId, status: 'paid' };
})
.addTo(app);
// 调用其他路由
app
.route({ path: 'dashboard', key: 'stats' })
.define(async (ctx) => {
// 调用 user/info 路由
const userRes = await ctx.run({ path: 'user', key: 'info', payload: { id: 1 } });
// 调用 product/list 路由
const productRes = await ctx.run({ path: 'product', key: 'list' });
ctx.body = {
user: userRes.data,
products: productRes.data,
};
})
.addTo(app);
// 使用 throw 抛出错误
app
.route({ path: 'admin', key: 'delete' })
.define(async (ctx) => {
const { id } = ctx.query;
if (!id) {
ctx.throw(400, '缺少参数', 'id is required');
}
ctx.body = { success: true };
})
.addTo(app);
中间件
import { App, Route } from '@kevisual/router';
const app = new App();
// 定义中间件
app
.route({
id: 'auth-example',
description: '权限校验中间件',
})
.define(async (ctx) => {
const token = ctx.query.token;
if (!token) {
ctx.throw(401, '未登录', '需要 token');
}
// 验证通过,设置用户信息到 state
ctx.state.tokenUser = { id: 1, name: '用户A' };
})
.addTo(app);
// 使用中间件(通过 id 引用)
app
.route({ path: 'admin', key: 'panel', middleware: ['auth-example'] })
.define(async (ctx) => {
// 可以访问中间件设置的 state
const { tokenUser } = ctx.state;
ctx.body = { tokenUser };
})
.addTo(app);
一个丰富的router示例
import { App } from '@kevisual/router';
const app = new App();
app
.router({
path: 'dog',
key: 'info',
description: '获取狗的信息',
metedata: {
args: {
owner: z.string().describe('狗主人姓名'),
age: z.number().describe('狗的年龄'),
},
},
})
.define(async (ctx) => {
const { owner, age } = ctx.query;
ctx.body = {
content: `这是一只${age}岁的狗,主人是${owner}`,
};
})
.addTo(app);
注意事项
-
path 和 key 的组合是路由的唯一标识,同一个 path+key 只能添加一个路由,后添加的会覆盖之前的。
-
ctx.call vs ctx.run:
call返回完整 context,包含所有属性run返回{ code, data, message }格式,data 即 body
-
ctx.throw 会自动结束执行,抛出自定义错误。
-
payload 会自动合并到 query,调用
ctx.run({ path, key, payload })时,payload 会合并到 query。 -
nextQuery 用于传递给 nextRoute,在当前路由中设置
ctx.nextQuery,会在执行 nextRoute 时合并到 query。 -
避免 nextRoute 循环调用,默认最大深度为 40 次,超过会返回 500 错误。
-
needSerialize 默认为 true,会自动对 body 进行 JSON 序列化和反序列化。
-
progress 记录执行路径,可用于调试和追踪路由调用链。
-
中间件找不到会返回 404,错误信息中会包含找不到的中间件列表。
Description
Languages
TypeScript
100%