如何基于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
- 初始化Prisma
执行命令生成Prisma配置文件:
npx prisma init
修改根目录下的.env文件,替换Postgres连接字符串:
DATABASE_URL="postgresql://你的用户名:你的密码@localhost:5432/数据库名?schema=public"
- 定义会话模型
在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 }
- 同步数据库
执行迁移命令创建会话表:
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
相关产品推荐
相关产品推荐

