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

在NestJS中通过MiddlewareConsumer使用fastifySession中间件遇阻求助

解决方案:NestJS + Fastify 中通过DI注册fastifySession及Passport插件

错误原因分析

你遇到的Root plugin has already booted错误,核心原因是Fastify插件必须在实例启动(调用listen)前完成注册,而Nest的Middleware是在请求处理阶段执行的——此时Fastify已经启动完成,无法再动态注册新插件。

正确实现方式

方案一:利用OnModuleInit钩子(推荐)

通过Nest的OnModuleInit生命周期钩子,在模块初始化完成、应用启动前注册Fastify插件,同时可以直接注入依赖服务(满足DI需求)。

import { Module, OnModuleInit, HttpAdapterHost } from '@nestjs/common';
import { fastifyCookie } from '@fastify/cookie';
import fastifySession from '@fastify/session';
import { Authenticator } from '@fastify/passport';
import { SessionStore } from './session.store';
import { UserService } from './user.service';
import { User } from './user.entity';

@Module({
  providers: [SessionStore, UserService],
})
export class AppModule implements OnModuleInit {
  private fastifyPassport: Authenticator;

  constructor(
    private readonly httpAdapterHost: HttpAdapterHost,
    private readonly sessionStore: SessionStore,
    private readonly userService: UserService,
  ) {
    this.fastifyPassport = new Authenticator();
  }

  async onModuleInit() {
    const httpAdapter = this.httpAdapterHost.httpAdapter;
    const fastifyInstance = httpAdapter.getInstance();

    // 先注册session依赖的cookie插件
    await fastifyInstance.register(fastifyCookie);

    // 注册session插件,使用DI注入的store
    await fastifyInstance.register(fastifySession, {
      secret: process.env.SESSION_SECRET || 'your-strong-secret', // 建议用环境变量
      cookie: {
        secure: false,
        maxAge: 50000,
        path: '/',
        httpOnly: true,
        sameSite: false,
        domain: 'localhost',
      },
      store: this.sessionStore,
    });

    // 初始化Passport
    await fastifyInstance.register(this.fastifyPassport.initialize());
    await fastifyInstance.register(this.fastifyPassport.secureSession());

    // 配置用户序列化/反序列化,依赖注入的UserService
    this.fastifyPassport.registerUserSerializer(async (user: User) => {
      return user.id;
    });

    this.fastifyPassport.registerUserDeserializer(async (id: string) => {
      return this.userService.getUser(+id);
    });
  }
}

方案二:自定义Fastify Adapter(适合深度定制场景)

如果需要对Fastify实例做更多初始化配置,可以自定义Adapter,在实例创建阶段完成插件注册。

1. 自定义Adapter

import { FastifyAdapter } from '@nestjs/platform-fastify';
import fastifyCookie from '@fastify/cookie';
import fastifySession from '@fastify/session';
import { Authenticator } from '@fastify/passport';
import { SessionStore } from './session.store';
import { UserService } from './user.service';
import { User } from './user.entity';

export class CustomFastifyAdapter extends FastifyAdapter {
  constructor(
    private readonly sessionStore: SessionStore,
    private readonly userService: UserService,
  ) {
    super();
  }

  async init(): Promise<void> {
    await super.init();

    const fastifyInstance = this.getInstance();
    const fastifyPassport = new Authenticator();

    await fastifyInstance.register(fastifyCookie);
    await fastifyInstance.register(fastifySession, {
      secret: process.env.SESSION_SECRET || 'your-strong-secret',
      cookie: {
        secure: false,
        maxAge: 50000,
        path: '/',
        httpOnly: true,
        sameSite: false,
        domain: 'localhost',
      },
      store: this.sessionStore,
    });

    await fastifyInstance.register(fastifyPassport.initialize());
    await fastifyInstance.register(fastifyPassport.secureSession());

    fastifyPassport.registerUserSerializer(async (user: User) => {
      return user.id;
    });

    fastifyPassport.registerUserDeserializer(async (id: string) => {
      return this.userService.getUser(+id);
    });
  }
}

2. 在main.ts中使用自定义Adapter

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { CustomFastifyAdapter } from './custom-fastify.adapter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // 从DI容器获取依赖服务
  const sessionStore = app.get('SessionStore');
  const userService = app.get('UserService');
  
  // 替换默认Adapter
  const adapter = new CustomFastifyAdapter(sessionStore, userService);
  app.useHttpAdapter(adapter);

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

关键说明

  • 两种方案都保证了Fastify插件在实例启动前完成注册,避开了"Root plugin已启动"的限制。
  • 均支持Nest的依赖注入,可以直接使用SessionStore、UserService等服务,无需手动实例化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:05:18