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

NextJS 15中多路由无法共享单例Vault实例问题

问题分析与解决方案

问题根源

你的单例在Next.js 15的两个路由中被重复创建,核心原因有两个:

  1. 开发模式的模块隔离与热重载:Next.js App Router在开发时,每个路由模块会被单独编译和热重载,模块级的instance变量会在路由重载时重置,导致重新创建实例。
  2. 生产环境的进程模型:如果部署在无服务器函数(如Vercel、Netlify)或Node.js集群模式下,每个进程拥有独立的内存空间,模块级单例仅在单个进程内有效,跨进程无法共享。

解决方案

方案1:开发测试用——基于全局对象的单例

利用Node.js的globalThis存储实例,避免模块重复加载导致的变量重置,适合开发单进程场景:

import { Vault } from './Vault';

type VaultType = Vault;

export function getOrCreateVaultInstance(keys?: Map<string, string>): Vault {
  // 用globalThis存储进程级实例
  if (!globalThis.vaultInstance) {
    console.info("✨ Creating a new vault instance ✨");
    globalThis.vaultInstance = new Vault(keys);
  }

  return globalThis.vaultInstance as Vault;
}

// 扩展TypeScript全局类型,避免类型报错
declare global {
  var vaultInstance: VaultType | undefined;
}

注意:开发模式下如果重启整个服务器进程,实例仍会重置,但单个路由热重载不会影响;生产单进程部署可正常共享。

方案2:生产环境推荐——外部缓存服务

内存单例无法跨进程/无服务器实例共享,生产环境必须用外部缓存存储验证码,比如Redis:

// 先安装依赖:npm install redis
import { createClient } from 'redis';

// 初始化Redis客户端(从环境变量读取配置)
const redisClient = createClient({ url: process.env.REDIS_URL });
redisClient.connect().catch(console.error);

// 存储验证码(设置5分钟过期)
export async function saveVerificationCode(email: string, code: string) {
  await redisClient.setEx(email, 300, code);
}

// 验证验证码
export async function verifyVerificationCode(email: string, code: string) {
  const storedCode = await redisClient.get(email);
  return storedCode === code;
}

优势:不受进程限制,数据持久化(可选),更符合生产环境的可靠性要求,同时避免服务器重启导致的数据丢失。


总结

  • 仅开发测试时,可使用globalThis实现单例共享;
  • 生产环境必须依赖外部缓存服务,这是Next.js部署模型下的唯一可靠方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 08:55:07