Inversify错误中间件对首个容器配置的最后路由抛出未处理错误
问题:首个导入的Inversify容器配置中最后一个路由报"Cannot set headers after they are sent to the client"错误
预期行为
未捕获的错误应通过错误中间件传递,并返回正确的错误信息。所有路由都应通过将错误传递给错误中间件实现一致行为。
当前行为
对于任何首个导入的容器配置,其最后一个路由会抛出如下错误:
Error: Cannot set headers after they are sent to the client at new NodeError (node:internal/errors:405:5) at ServerResponse.setHeader (node:_http_outgoing:648:11) at processTicksAndRejections (node:internal/process/task_queues:95:5) at runNextTicks (node:internal/process/task_queues:64:3) at processImmediate (node:internal/timers:447:9)
复现步骤
controller.ts
import { Request, Response, NextFunction } from 'express'; import { injectable } from 'inversify'; import { BaseController } from '@sn/server'; import { AppError } from '@sn/core'; import { logDecorator } from '@sn/shared'; @injectable() export class GetMetaController extends BaseController { constructor() { super(); } @logDecorator() public async executeImpl( request: Request, response: Response, next: NextFunction ): Promise<any> { try { throw new Error('Throw some error'); // return this.ok<any>(response, { user: 1 }); } catch (err: any) { return this.fail(response, new AppError.UnexpectedError(err), next); } } }
route.ts
import { NextFunction, Request, Response } from 'express'; import { inject } from 'inversify'; import { controller, httpGet } from 'inversify-express-utils'; import { ApiPath } from 'swagger-express-ts'; import TYPES from '@ioc/constant/Types'; import { GetRefVersionController } from '../controller/GetRefVersionController'; import { GetMetaController } from '../controller/GetMetaController'; @ApiPath({ name: 'RefVersions', path: '/refVersion' }) @controller('/refVersion') export abstract class RefVersionRouters { constructor( @inject(TYPES.GetRefVersionController) private readonly _getRefVersionController: GetRefVersionController, @inject(TYPES.GetMetaController) private readonly _getMeta: GetMetaController ) {} @httpGet('/version') public async getAllRefVersion( request: Request, response: Response, next: NextFunction ) { return this._getRefVersionController.execute(request, response, next); } @httpGet('/meta') public async getMeta( request: Request, response: Response, next: NextFunction ) { return this._getMeta.execute(request, response, next); } }
module_config.ts
import { AsyncContainerModule, interfaces } from 'inversify'; import { errorHandler } from '@core/error/ErrorHandler'; import TYPES from '@ioc/constant/Types'; import { RefVersionRouters } from './infrastructure/routers/RefVersionRouter'; import { GetRefVersionController } from './infrastructure/controller/GetRefVersionController'; import { GetMetaController } from './infrastructure/controller/GetMetaController'; const SystemConfigContainer = new AsyncContainerModule( async (bind: interfaces.Bind) => { try { RefVersionRouters; bind<GetRefVersionController>(TYPES.GetRefVersionController) .to(GetRefVersionController) .inRequestScope(); bind<GetMetaController>(TYPES.GetMetaController) .to(GetMetaController) .inRequestScope(); } catch (err: unknown) { errorHandler.handleError('SystemIOC Error', err as Error); } } ); export { SystemConfigContainer };
Ioc_config.ts
import { Container } from 'inversify'; import { errorHandler } from '@core/error/ErrorHandler'; import TYPES from './constant/Types'; import { SystemConfigContainer } from '@system-module/SystemIocConfig'; import { CheckConfigContainer } from '../module/check/CheckConfig'; import { UserConfigContainer } from '@user-module/UserIocConfig'; const InversifyConfigContainer = async () => { const container = new Container(); try { container.loadAsync(SystemConfigContainer); container.loadAsync(UserConfigContainer); container.loadAsync(CheckConfigContainer); } catch (err: unknown) { errorHandler.handleError('IOC Error', err as Error); } return container; }; export { InversifyConfigContainer };
AppServer.ts
import 'reflect-metadata'; /* eslint-disable @typescript-eslint/no-explicit-any */ // eslint-disable-next-line @typescript-eslint/no-var-requires require('source-map-support').install(); import * as dotenv from 'dotenv'; import { InversifyExpressServer } from 'inversify-express-utils'; import { ExpressMiddleware, errorMiddleware } from './../middleware'; import { logger } from '@sn/shared'; // import { envConfig } from './config'; // import { ExitProcess } from './core/utils/ExitProcess'; dotenv.config(); const port = process.env.PORT || 3000; export const appServer = async (config: any): Promise<void> => { try { const server = new InversifyExpressServer(config, null, { rootPath: '/api/v1' }); /* Adding middleware to express server */ server.setConfig((app) => { new ExpressMiddleware(app); }); server.setErrorConfig(errorMiddleware); const serverInstance = server.build(); serverInstance.listen(port, () => { logger.info(`Server running at http://127.0.0.1:${port}/`); }); // ExitProcess(server); } catch (err) { logger.error('Error in SERVER', err); } };
MainAppServer.ts
import 'module-alias/register'; import 'reflect-metadata'; import { InversifyConfigContainer } from '@ioc/IocConfig'; import sourceMapSupport from 'source-map-support'; import { logger } from '@sn/shared'; import { appServer } from '@sn/server'; sourceMapSupport.install(); const expressApp = (async (): Promise<void> => { /* Setting up IoC */ try { const containerConfig = await InversifyConfigContainer(); await appServer(containerConfig); } catch (err) { logger.error('Error', err); } })(); expressApp;
上下文信息
当导入顺序如下时:
import { SystemConfigContainer } from '@system-module/SystemIocConfig'; import { CheckConfigContainer } from '../module/check/CheckConfig'; import { UserConfigContainer } from '@user-module/UserIocConfig';
首个导入的SystemConfigContainer的最后一个路由会抛出“请求已发送”的错误。
如果修改导入顺序为:
import { CheckConfigContainer } from '../module/check/CheckConfig'; import { SystemConfigContainer } from '@system-module/SystemIocConfig'; import { UserConfigContainer } from '@user-module/UserIocConfig';
则首个导入的CheckConfigContainer的最后一个路由会抛出该错误,其余所有路由均正常工作。
环境信息
- "inversify": "^6.0.1"
- "inversify-express-utils": "^6.4.3"
- nodejs: 18+
- MacOs
堆栈跟踪
对于任何首个导入的容器配置,其最后一个路由会抛出如下错误: Error: Cannot set headers after they are sent to the client at new NodeError (node:internal/errors:405:5) at ServerResponse.setHeader (node:_http_outgoing:648:11) at processTicksAndRejections (node:internal/process/task_queues:95:5) at runNextTicks (node:internal/process/task_queues:64:3) at processImmediate (node:internal/timers:447:9)
内容的提问来源于stack exchange,提问作者Mr X
相关产品推荐
相关产品推荐

