You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 14:35:04