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;