NestJS+Fastify部署SPA刷新触发404,调用sendFile报FST_ERR_REP_ALREADY_SENT
解决NestJS + Fastify部署SPA刷新404及FST_ERR_REP_ALREADY_SENT错误
问题根源
刷新SPA页面出现404是因为前端路由在后端没有对应匹配项,Fastify会抛出NotFoundException。而FST_ERR_REP_ALREADY_SENT错误是因为异常过滤器触发时,Fastify已经开始发送响应头,此时调用sendFile会导致重复发送响应。
最优解决方案:配置Fastify路由Fallback(无需异常过滤器)
直接让Fastify对所有非API的GET请求返回index.html,这是SPA部署的标准做法,避免异常抛出和重复响应问题。
修改main.ts代码:
import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; import { join } from 'path'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter(), ); // 配置静态资源目录(替换为你的SPA构建产物路径,比如dist/spa) app.useStaticAssets({ root: join(__dirname, '..', 'dist', 'spa'), prefix: '/', }); // 所有未匹配的GET请求返回index.html app.get('*', (req, res) => { res.sendFile('index.html', join(__dirname, '..', 'dist', 'spa')); }); await app.listen(3000); } bootstrap();
异常过滤器修复方案(如果必须使用过滤器)
如果坚持用异常过滤器捕获404,需要先检查响应是否已发送,并确保sendFile路径正确:
- 修改过滤器代码:
import { Catch, ExceptionFilter, ArgumentsHost, NotFoundException } from '@nestjs/common'; import { FastifyReply } from 'fastify'; import { join } from 'path'; @Catch(NotFoundException) export class NotFoundExceptionFilter implements ExceptionFilter { catch(_exception: NotFoundException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse() as FastifyReply; // 仅在响应未发送时处理 if (!response.sent) { response.type('text/html'); // 指定index.html的绝对路径,或通过root参数设置根目录 response.sendFile('index.html', { root: join(__dirname, '..', 'dist', 'spa'), }); } } }
- 全局注册过滤器(在
main.ts中添加):
app.useGlobalFilters(new NotFoundExceptionFilter());
注意事项
- 确保
sendFile的路径正确,使用绝对路径或配置root参数指向SPA构建目录。 - 优先选择路由Fallback方案,更高效且符合SPA部署的最佳实践。
内容的提问来源于stack exchange,提问作者Cavdy
相关产品推荐
相关产品推荐

