如何在使用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插件,可控性更高:
- 先移除之前
AppModule中导入的ServeStaticModule - 修改
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
相关产品推荐
相关产品推荐

