ES6 Class 路由控制器应将请求逻辑封装为类实例,构造函数仅初始化依赖,handler 方法接收 ctx 和 next,通过箭头函数、constructor 绑定或 call/apply 确保 this 正确,推荐复用实例而非每次 new,服务层单例、Controller 轻量可复用。

用 ES6 Class 编写路由控制器,核心是把请求处理逻辑封装成类实例,同时解决 this 绑定、依赖复用和生命周期管理问题。关键不在“能不能写”,而在于“怎么写才不踩坑”——比如常见报错 fn() of undefined,往往就是 this 丢失导致的。
构造函数里不直接操作请求响应
Class 不该在 constructor 中接收 ctx 或 req/res,因为控制器实例通常复用,而每次请求上下文不同。正确做法是把具体处理逻辑放在异步方法里,由路由层传入当前请求对象:
- 构造函数只负责初始化依赖(如 service、logger)
- 每个路由 handler(如
getBluetoochList)接收ctx和next,保持函数式调用语义 - 避免在 handler 内部用
new this.constructor()创建新实例——容易引发内存泄漏或状态错乱
方法调用必须保证 this 指向正确
ES6 Class 默认不自动绑定 this,尤其在回调、定时器或解构调用时极易丢失。有三种稳妥方式:
-
箭头函数定义方法:适用于内部逻辑简单、不需被外部重绑定的私有工具方法(如
getCustomerByOrgId) -
在 constructor 中显式绑定:
this.getCustomerByOrgId = this.getCustomerByOrgId.bind(this) -
调用时用 call/apply:适合临时场景,例如
this.getCustomerByOrgId.call(this, org_id)
切忌在异步链中直接写 this.fn() 而不确认执行上下文——Node.js 的回调机制会让 this 变成 undefined。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
单例模式不是必须,但推荐按需实例化
Controller 类本身应是无状态的“模板”,真正需要单例的是它所依赖的服务(如数据库连接池、日志器)。实际开发中更合理的做法是:
- 每个请求使用同一个 Controller 实例(通过 DI 容器或手动注入)
- 服务层(Service)用单例,Controller 层保持轻量、可复用
- 若真要单例 Controller,建议用静态属性缓存实例,并加锁防止并发初始化
像 const controller = new BluetoochController() 放在模块顶层,比每次 handler 里 new 一次更安全高效。
配合路由框架做装饰器或注册式集成
纯 Node.js 可手动映射,但工程化项目建议借助框架能力:
- NestJS:用
@Controller()+@Get()等装饰器,Class 自动绑定路由 - Express:导出类实例,再用
router.get('/list', controller.getBluetoochList.bind(controller)) - Koa:支持中间件式写法,
router.get('/list', controller.getBluetoochList)前确保已 bind
装饰器本质是语法糖,底层仍是 Class 方法注册;手动绑定虽啰嗦,但更透明、易调试。


















