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

如何基于NestJS、Prisma与Postgres搭建会话存储?

使用NestJS + Prisma + Postgres 搭建会话存储

一、依赖安装

首先初始化Nest项目并安装核心依赖:

# 初始化Nest项目(若未创建)
nest new nest-prisma-session-demo
cd nest-prisma-session-demo

# 安装会话、Prisma及Postgres驱动依赖
npm install @nestjs/express-session @prisma/client pg express-session

# 安装Prisma CLI(开发依赖)
npm install prisma --save-dev

二、配置Prisma与Postgres

  1. 初始化Prisma
    执行命令生成Prisma配置文件:
npx prisma init

修改根目录下的.env文件,替换Postgres连接字符串:

DATABASE_URL="postgresql://你的用户名:你的密码@localhost:5432/数据库名?schema=public"
  1. 定义会话模型
    在prisma/schema.prisma中添加Session表结构:
model Session {
  id           String   @id @default(cuid())
  sessionId    String   @unique // 对应会话ID
  userId       String?  // 关联用户ID(可选)
  expires      DateTime // 会话过期时间
  data         String   @db.Text // 存储序列化的会话数据
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
}
  1. 同步数据库
    执行迁移命令创建会话表:
npx prisma migrate dev --name init-session-table

同时会自动生成Prisma Client供代码调用。

三、实现Prisma会话存储适配器

创建session-store.service.ts,实现express-session的Store接口:

import { Injectable } from '@nestjs/common';
import { Store } from 'express-session';
import { PrismaService } from './prisma.service';

@Injectable()
export class PrismaSessionStore extends Store {
  constructor(private readonly prisma: PrismaService) {
    super();
  }

  // 获取会话
  async get(sessionId: string, callback: (err: any, session?: any) => void) {
    try {
      const sessionRecord = await this.prisma.session.findUnique({
        where: { sessionId },
      });

      if (!sessionRecord) return callback(null, null);

      // 检查会话是否过期
      if (new Date() > sessionRecord.expires) {
        await this.destroy(sessionId);
        return callback(null, null);
      }

      callback(null, JSON.parse(sessionRecord.data));
    } catch (err) {
      callback(err);
    }
  }

  // 存储/更新会话
  async set(sessionId: string, session: any, callback?: (err?: any) => void) {
    try {
      await this.prisma.session.upsert({
        where: { sessionId },
        update: {
          expires: new Date(session.cookie.expires),
          data: JSON.stringify(session),
        },
        create: {
          sessionId,
          expires: new Date(session.cookie.expires),
          data: JSON.stringify(session),
        },
      });
      callback?.();
    } catch (err) {
      callback?.(err);
    }
  }

  // 销毁会话
  async destroy(sessionId: string, callback?: (err?: any) => void) {
    try {
      await this.prisma.session.delete({ where: { sessionId } });
      callback?.();
    } catch (err) {
      callback?.(err);
    }
  }

  // 清理过期会话(定时任务调用)
  async clearExpired() {
    await this.prisma.session.deleteMany({
      where: { expires: { lt: new Date() } },
    });
  }
}

同时创建prisma.service.ts封装Prisma Client:

import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

四、配置NestJS会话中间件

修改app.module.ts,集成会话模块并使用自定义存储:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SessionModule } from '@nestjs/express-session';
import { PrismaSessionStore } from './session-store.service';
import { PrismaService } from './prisma.service';

@Module({
  imports: [
    SessionModule.forRoot({
      secret: process.env.SESSION_SECRET || 'dev-secret-key', // 生产环境用环境变量
      resave: false,
      saveUninitialized: false,
      cookie: {
        secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPS
        httpOnly: true,
        maxAge: 24 * 60 * 60 * 1000, // 会话有效期1天
        sameSite: 'strict',
      },
      store: new PrismaSessionStore(new PrismaService()),
    }),
  ],
  controllers: [AppController],
  providers: [AppService, PrismaService, PrismaSessionStore],
})
export class AppModule {}

五、测试会话功能

在控制器中添加测试接口:

// app.controller.ts
import { Controller, Get, Post, Session } from '@nestjs/common';

@Controller()
export class AppController {
  @Post('/set-session')
  setSession(@Session() session: Record<string, any>) {
    session.userId = 'user_1001';
    session.nickname = 'test_user';
    return { msg: '会话已设置' };
  }

  @Get('/get-session')
  getSession(@Session() session: Record<string, any>) {
    return { userId: session.userId, nickname: session.nickname };
  }

  @Post('/destroy-session')
  destroySession(@Session() session: Record<string, any>) {
    session.destroy();
    return { msg: '会话已销毁' };
  }
}

启动项目后调用接口,可通过Prisma Studio(npx prisma studio)查看Postgres中Session表的变化。

六、生产环境优化建议

  • 用环境变量管理DATABASE_URL、SESSION_SECRET等敏感信息
  • 集成NestJS的@nestjs/schedule模块,定时调用clearExpired清理过期会话
  • 启用Postgres连接池,优化数据库性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:30:50