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中同时做了两项导致路由重复的配置:
- 在
imports数组中导入了BatchModule - 在
controllers数组中手动注册了BatchController
如果BatchModule内部已经在自身的controllers数组中声明了BatchController,那么AppModule的这两项配置会让BatchController被Nest重复注册两次,生成两条完全一样的POST /batch/create路由。Fastify对路由重复的校验比Express严格,因此直接抛出错误,而Express会静默覆盖重复路由,所以切换适配器后问题消失。
修复步骤
- 检查
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 {}
- 确认
BatchModule已包含BatchController后,删除AppModule的controllers数组中的BatchController项,只保留BatchModule在imports数组中即可:
// 修改后的AppModule controllers数组 controllers: [ MedicationController, // 移除BatchController EncounterTypeController, PractionerController, PatientController, AppController, ],
- 同时,
AppModule的providers数组中的BatchService、BatchRepository也可以移除,因为这些服务应该由BatchModule提供(如果需要在其他模块使用,可通过BatchModule的exports字段对外暴露)。
修改完成后,BatchController只会被注册一次,Fastify就不会再抛出路由重复的错误了。
内容的提问来源于stack exchange,提问作者MARCOS FELIPE BARBOSA DE CARVA
相关产品推荐
相关产品推荐

