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

Nest.js + Fastify Adapter 路由重复错误的解决方法

问题

使用Nest.js + Fastify Adapter开发时,实现了BatchController类及create方法:类添加@Controller('batch')装饰器,方法添加@Post('create')装饰器。确认无其他类使用该路由,但出现错误:

FastifyError: Method 'POST' already declared for route '/batch/create'

切换到Express适配器后错误消失,但需要在Fastify环境下解决该问题。

相关代码

main.ts(Fastify适配器版本)

import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );
  app.enableCors();
  await app.listen(3000);
}

bootstrap();

BatchController类

import { Body, Controller, Post } from '@nestjs/common';
import { BatchService } from './batch.service';
import { ResponseBody } from 'src/interface/response.body';
import { CreateBatchDto } from './dto/create.batch.dto';

@Controller('batch')
export class BatchController {

    constructor (
        private batchService: BatchService
    ) {}

    @Post('create')
    async create(@Body() body: CreateBatchDto): Promise<ResponseBody> {
        return await this.batchService.create(body);
    }

}

app.module.ts

// Module
import { Module } from '@nestjs/common';
import { LogModule } from './core/log/log.module';
import { PatientModule } from './core/patient/patient.module';

// This is import of BatchModule
import { BatchModule } from './core/batch/batch.module';

import { MedicationModule } from './core/medication/medication.module';
import { EncounterTypeModule } from './core/encounter-type/encounter-type.module';
import { PractionerModule } from './core/practioner/practioner.module';

// Controller
import { AppController } from './app.controller';
import { PatientController } from './core/patient/patient.controller';

// This is import of BatchController
import { BatchController } from './core/batch/batch.controller';

import { MedicationController } from './core/medication/medication.controller';
import { EncounterTypeController } from './core/encounter-type/encounter-type.controller';
import { PractionerController } from './core/practioner/practioner.controller';

// Service
import { PrismaService } from './service/prisma.service';
import { AppService } from './app.service';
import { PatientService } from './core/patient/patient.service';
import { MedicationService } from './core/medication/medication.service';
import { BatchService } from './core/batch/batch.service';
import { EncounterTypeService } from './core/encounter-type/encounter-type.service';
import { PractionerService } from './core/practioner/practioner.service';

// Repository
import { PatientRepository } from './core/patient/patient.repository';
import { MedicationRepository } from './core/medication/medication.repository';
import { BatchRepository } from './core/batch/batch.repository';
import { PractitionerRepository } from './core/practioner/practioner.repository';
import { EncounterTypeRepository } from './core/encounter-type/encounter-type.repository';

// Util
import { DefaultUtil } from './util/default.util';
import { ObjectUtil } from './util/object.util';
import { DocumentUtil } from './util/document.util';
import { DateUtil } from './util/date.util';

@Module({
  imports: [
    MedicationModule,
    BatchModule,
    EncounterTypeModule,
    PractionerModule,
    PatientModule,
    LogModule
  ],
  controllers: [
    MedicationController,
    BatchController,
    EncounterTypeController,
    PractionerController,
    PatientController,
    AppController,
  ],
  providers: [
    // Service
    BatchService,
    PatientService,
    PrismaService,
    PractionerService,
    AppService,
    EncounterTypeService,
    MedicationService,
    // Repository
    PatientRepository,
    PractitionerRepository,
    EncounterTypeRepository,
    BatchRepository,
    MedicationRepository,
    // Util
    DefaultUtil,
    ObjectUtil,
    DocumentUtil,
    DateUtil
  ],
})

export class AppModule { }

错误详情

/Users/marcos/Documents/GitHub/HC/res/node_modules/fastify/lib/route.js:367
            throw new FST_ERR_DUPLICATED_ROUTE(opts.method, opts.url)
                  ^
FastifyError: Method 'POST' already declared for route '/batch/create'
    at Object.addNewRoute (/Users/marcos/Documents/GitHub/HC/res/node_modules/fastify/lib/route.js:367:19)
    at Object.route (/Users/marcos/Documents/GitHub/HC/res/node_modules/fastify/lib/route.js:261:19)
    at Object.prepareRoute (/Users/marcos/Documents/GitHub/HC/res/node_modules/fastify/lib/route.js:167:18)
    at Object._post [as post] (/Users/marcos/Documents/GitHub/HC/res/node_modules/fastify/fastify.js:271:34)
    at FastifyAdapter.injectRouteOptions (/Users/marcos/Documents/GitHub/HC/res/node_modules/@nestjs/platform-fastify/adapters/fastify-adapter.js:395:46)
    at FastifyAdapter.post (/Users/marcos/Documents/GitHub/HC/res/node_modules/@nestjs/platform-fastify/adapters/fastify-adapter.js:129:21)
    at /Users/marcos/Documents/GitHub/HC/res/node_modules/@nestjs/core/router/router-explorer.js:105:17
    at Array.forEach (<anonymous>)
    at /Users/marcos/Documents/GitHub/HC/res/node_modules/@nestjs/core/router/router-explorer.js:90:29
    at Array.forEach (<anonymous>)

解决方法

问题根源

你在AppModule中同时做了两项导致路由重复的配置:

  1. 在imports数组中导入了BatchModule
  2. 在controllers数组中手动注册了BatchController

如果BatchModule内部已经在自身的controllers数组中声明了BatchController,那么AppModule的这两项配置会让BatchController被Nest重复注册两次,生成两条完全一样的POST /batch/create路由。Fastify对路由重复的校验比Express严格,因此直接抛出错误,而Express会静默覆盖重复路由,所以切换适配器后问题消失。

修复步骤

  1. 检查BatchModule的代码,确认它是否已经声明了BatchController。正常的模块结构应该类似:
// batch.module.ts
import { Module } from '@nestjs/common';
import { BatchController } from './batch.controller';
import { BatchService } from './batch.service';

@Module({
  controllers: [BatchController],
  providers: [BatchService]
})
export class BatchModule {}
  1. 确认BatchModule已包含BatchController后,删除AppModule的controllers数组中的BatchController项,只保留BatchModule在imports数组中即可:
// 修改后的AppModule controllers数组
controllers: [
  MedicationController,
  // 移除BatchController
  EncounterTypeController,
  PractionerController,
  PatientController,
  AppController,
],
  1. 同时,AppModule的providers数组中的BatchService、BatchRepository也可以移除,因为这些服务应该由BatchModule提供(如果需要在其他模块使用,可通过BatchModule的exports字段对外暴露)。

修改完成后,BatchController只会被注册一次,Fastify就不会再抛出路由重复的错误了。


内容的提问来源于stack exchange,提问作者MARCOS FELIPE BARBOSA DE CARVA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:45:12