// 自动扫描 controllers 目录并注册路由 // 兼容传统 routes 方式和自动注册 controller 方式 import fs from "fs" import path from "path" /** * 自动扫描 controllers 目录,注册所有导出的路由 * 自动检测 routes 目录下已手动注册的 controller,避免重复注册 * @param {Koa} app - Koa 实例 * @param {string} controllersDir - controllers 目录路径 * @param {string} prefix - 路由前缀 * @param {Set} [manualControllers] - 可选,手动传入已注册 controller 文件名集合,优先于自动扫描 */ export function autoRegisterControllers(app, controllersDir = path.resolve(__dirname, "../controllers")) { let allRouter = [] async function scan(dir, routePrefix = "") { for (const file of fs.readdirSync(dir)) { const fullPath = path.join(dir, file) const stat = fs.statSync(fullPath) if (stat.isDirectory()) { await scan(fullPath, routePrefix + "/" + file) } else if (file.endsWith("Controller.js")) { let controller try { controller = require(fullPath) } catch (e) { controller = (await import(fullPath)).default } const routes = controller.createRoutes || controller.default?.createRoutes || controller.default || controller if (typeof routes === "function") { allRouter.push(routes()) } } } } ;(async () => { await scan(controllersDir) // TODO: 存在问题:每个Controller都是有顺序的,如果其中一个Controller没有next方法,可能会导致后续的Controller无法执行 allRouter.forEach(router => { app.use(router.middleware()) }) // // 聚合中间件:只分发到匹配的router // app.use(async (ctx, next) => { // let matched = false // for (const router of allRouter) { // // router._matchRoute 只在 router.js 内部,需暴露或用 middleware 包一层 // if (typeof router._matchRoute === "function") { // const route = router._matchRoute(ctx.method.toLowerCase(), ctx.path) // if (route) { // matched = true // await router.middleware()(ctx, next) // break // 命中一个即停止 // } // } else { // // fallback: 直接尝试middleware,若未命中会自动next // const before = ctx.status // await router.middleware()(ctx, next) // if (ctx.status !== before) { // matched = true // break // } // } // } // if (!matched) { // await next() // } // }) })() }