You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.6 KiB
106 lines
2.6 KiB
import { match } from 'path-to-regexp';
|
|
import compose from 'koa-compose';
|
|
|
|
class Router {
|
|
/**
|
|
* 初始化路由实例
|
|
* @param {Object} options - 路由配置
|
|
* @param {string} options.prefix - 全局路由前缀
|
|
*/
|
|
constructor(options = {}) {
|
|
this.prefix = options.prefix || '';
|
|
this.routes = { get: [], post: [], put: [], delete: [] };
|
|
this.middlewares = [];
|
|
}
|
|
|
|
/**
|
|
* 注册中间件
|
|
* @param {Function} middleware - 中间件函数
|
|
*/
|
|
use(middleware) {
|
|
this.middlewares.push(middleware);
|
|
}
|
|
|
|
/**
|
|
* 注册GET路由
|
|
* @param {string} path - 路由路径
|
|
* @param {Function} handler - 处理函数
|
|
*/
|
|
get(path, handler) {
|
|
this._registerRoute('get', path, handler);
|
|
}
|
|
|
|
/**
|
|
* 注册POST路由
|
|
* @param {string} path - 路由路径
|
|
* @param {Function} handler - 处理函数
|
|
*/
|
|
post(path, handler) {
|
|
this._registerRoute('post', path, handler);
|
|
}
|
|
|
|
/**
|
|
* 创建路由组
|
|
* @param {string} prefix - 组内路由前缀
|
|
* @param {Function} callback - 组路由注册回调
|
|
*/
|
|
group(prefix, callback) {
|
|
const groupRouter = new Router({ prefix: this.prefix + prefix });
|
|
callback(groupRouter);
|
|
// 合并组路由到当前路由
|
|
Object.keys(groupRouter.routes).forEach(method => {
|
|
this.routes[method].push(...groupRouter.routes[method]);
|
|
});
|
|
this.middlewares.push(...groupRouter.middlewares);
|
|
}
|
|
|
|
/**
|
|
* 生成Koa中间件
|
|
* @returns {Function} Koa中间件函数
|
|
*/
|
|
middleware() {
|
|
return async (ctx, next) => {
|
|
const { method, path } = ctx;
|
|
const route = this._matchRoute(method.toLowerCase(), path);
|
|
|
|
// 组合所有中间件和 handler
|
|
const middlewares = [...this.middlewares];
|
|
if (route) {
|
|
ctx.params = route.params;
|
|
middlewares.push(route.handler);
|
|
}
|
|
|
|
// 用 koa-compose 组合
|
|
const composed = compose(middlewares);
|
|
await composed(ctx, next);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 内部路由注册方法
|
|
* @private
|
|
*/
|
|
_registerRoute(method, path, handler) {
|
|
const fullPath = this.prefix + path;
|
|
const keys = [];
|
|
const matcher = match(fullPath, { decode: decodeURIComponent });
|
|
this.routes[method].push({ path: fullPath, matcher, keys, handler });
|
|
}
|
|
|
|
/**
|
|
* 匹配路由
|
|
* @private
|
|
*/
|
|
_matchRoute(method, currentPath) {
|
|
const routes = this.routes[method] || [];
|
|
for (const route of routes) {
|
|
const matchResult = route.matcher(currentPath);
|
|
if (matchResult) {
|
|
return { ...route, params: matchResult.params };
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export default Router;
|