NestJS 8.0以下版本调用app.resolve报getInstanceByContextId未定义如何解决
问题原因
这个报错是NestJS 8.0.0以下版本的已知设计问题:v8之前的版本里,NestFactory.create() 返回应用实例时,DI容器的上下文并没有完成完全初始化,负责按上下文ID查找实例的内部模块引用对象还未挂载,此时调用app.resolve() 触发实例查找逻辑时,就会因为读取undefined对象的getInstanceByContextId方法抛出类型错误。
本质上v8之前的app.resolve() 方法就没有对bootstrap启动阶段的调用场景做适配,它的设计预期是在应用完成初始化、进入运行态后(比如请求处理流程中、app.listen() 执行完成后)调用,用来解析transient、request作用域的提供者。
修复方案
可以根据项目实际情况任选一种方案修复:
- 升级NestJS版本到8.0.0及以上
8.0.0版本官方重构了应用初始化和DI容器的挂载流程,修正了这个时序问题,原有复现代码不需要做任何修改,就可以正常在app.listen()调用前通过app.resolve()解析transient作用域的Logger实例。 - 低版本兼容方案:提前手动触发应用初始化
如果暂时不能升级Nest大版本,只需要在调用app.resolve()之前先执行await app.init(),手动触发全量初始化流程,等DI上下文完全挂载后再做实例解析即可,修改后的代码如下:
async function bootstrap() { const app = await NestFactory.create(AppModule); // 低版本需先手动完成应用初始化,挂载DI容器上下文 await app.init(); const logger = await app.resolve<AbstractLoggerService>(LOGGER_TOKEN); logger.setContext('bootstrap'); app.useLogger(logger); await app.listen(3000); }
- 调整提供者注册逻辑
如果Logger不需要严格保持transient作用域,也可以直接把Logger注册为单例提供者,在bootstrap阶段直接用app.get(LOGGER_TOKEN)获取实例传入useLogger即可,不需要调用resolve方法,也能避开这个时序问题。
内容的提问来源于stack exchange,提问作者Timur
相关产品推荐
相关产品推荐

