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

如何在使用Fastify的NestJS项目中托管多个单页应用(SPA)

报错原因

报错的根本原因是 fastify-static 插件每次注册时默认会给Reply实例添加sendFile装饰器,而Fastify不允许重复注册同名装饰器。你用的@nestjs/serve-static封装层在传入多个静态配置、或者多次调用forRoot时,底层会多次注册fastify-static插件,默认配置下就会触发该报错。


解决方案一:修改现有ServeStaticModule配置

将所有静态配置统一放到单个forRoot调用中传入,除第一个配置外,其余所有配置的serveStaticOptions新增decorateReply: false参数,跳过重复的装饰器注册即可。
修改后的配置如下:

export const serveStaticModule_one: ServeStaticModuleOptions = {
    rootPath: join(process.cwd(), 'one')
    // 第一个配置保留默认,正常注册sendFile装饰器
};

export const serveStaticModule_two: ServeStaticModuleOptions = {
    rootPath: join(process.cwd(), 'two'),
    renderPath: '/two',
    serveStaticOptions: {
        decorateReply: false // 新增:跳过装饰器注册
    }
};

export const serveStaticModule_three: ServeStaticModuleOptions = {
    rootPath: join(process.cwd(), 'three'),
    renderPath: '/three',
    serveStaticOptions: {
        index: 'client.html',
        decorateReply: false // 新增:跳过装饰器注册
    }
};

// 模块注册时统一放到同一个forRoot调用
@Module({
  imports: [
    ServeStaticModule.forRoot(
      serveStaticModule_one,
      serveStaticModule_two,
      serveStaticModule_three
    )
  ]
})
export class AppModule {}

解决方案二:手动注册fastify-static(兼容性更强)

如果方案一不生效,可以直接跳过@nestjs/serve-static的封装,手动注册fastify-static插件,可控性更高:

  1. 先移除之前AppModule中导入的ServeStaticModule
  2. 修改main.ts代码如下:
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
import { join } from 'path';
import fastifyStatic from 'fastify-static';

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

  // 注册第一个SPA
  await app.register(fastifyStatic, {
    root: join(process.cwd(), 'one'),
    prefix: '/',
  });

  // 注册第二个SPA
  await app.register(fastifyStatic, {
    root: join(process.cwd(), 'two'),
    prefix: '/two/',
    decorateReply: false,
  });

  // 注册第三个SPA
  await app.register(fastifyStatic, {
    root: join(process.cwd(), 'three'),
    prefix: '/three/',
    index: 'client.html',
    decorateReply: false,
  });

  // 可选配置:如果前端用了history路由模式,添加404 fallback处理
  app.setNotFoundHandler((req, res) => {
    if (req.raw.url?.startsWith('/two')) {
      return res.sendFile('index.html', join(process.cwd(), 'two'));
    } else if (req.raw.url?.startsWith('/three')) {
      return res.sendFile('client.html', join(process.cwd(), 'three'));
    } else {
      return res.sendFile('index.html', join(process.cwd(), 'one'));
    }
  });

  await app.listen(3000);
}
bootstrap();

内容的提问来源于stack exchange,提问作者Amit Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:06:02