Next.js API无法获取更新后的密钥,开发与生产环境均存在问题
问题描述
使用Next.js构建后端API时,utils文件夹中的getSecrets函数负责从Azure密钥库获取密钥,但始终返回过时的值,该问题在开发和生产环境中均存在。
相关代码如下:
getSecrets函数代码
import { Env_Keys } from "@/types/customType"; import { DefaultAzureCredential } from "@azure/identity"; import { SecretClient } from "@azure/keyvault-secrets"; export const dynamic = "force-dynamic"; const credential = new DefaultAzureCredential(); const vaultName = ""; const url = `https://${vaultName}.vault.azure.net`; const client = new SecretClient(url, credential); let secrets: Env_Keys | null = null; async function getSecrets() { if (secrets === null) { const secretNames = [ "Test", ]; const secretPromises = secretNames.map((secretName) => client .getSecret(secretName) .then((secret) => ({ [secretName]: secret.value })) .catch((error) => { console.error(`Failed to get secret ${secretName}: ${error}`); return { [secretName]: null }; }) ); const secretObjects = await Promise.all(secretPromises); secrets = Object.assign({}, ...secretObjects); } return secrets; } export default getSecrets;
API路由代码
import getSecrets from "@/lib/read-keyvaults-secrets"; import { NextResponse } from "next/server"; export const dynamic = "force-dynamic"; export async function GET() { try { const secrets = await getSecrets(); return NextResponse.json( { secrets: { ...secrets, date: new Date().toISOString(), }, }, { status: 200, statusText: "OK", } ); } catch (error) { return NextResponse.json( { error: "An error occurred while fetching the secrets", }, { status: 500, statusText: "Internal Server Error", } ); } }
问题原因
核心问题在于模块级的secrets变量缓存。在Next.js的服务器运行环境中,模块会被加载一次并持久化,secrets变量第一次赋值后就不会再被重置,后续调用getSecrets都会直接返回这个旧值,完全跳过了重新请求Azure密钥库的逻辑。即使设置了dynamic: "force-dynamic",也只影响路由的渲染策略,无法清除模块级变量的缓存。
解决方案
方案1:移除模块级缓存,每次请求都拉取最新密钥
直接去掉secrets全局变量,每次调用getSecrets都重新从密钥库获取:
import { Env_Keys } from "@/types/customType"; import { DefaultAzureCredential } from "@azure/identity"; import { SecretClient } from "@azure/keyvault-secrets"; export const dynamic = "force-dynamic"; const credential = new DefaultAzureCredential(); const vaultName = ""; const url = `https://${vaultName}.vault.azure.net`; const client = new SecretClient(url, credential); async function getSecrets() { const secretNames = [ "Test", ]; const secretPromises = secretNames.map((secretName) => client .getSecret(secretName) .then((secret) => ({ [secretName]: secret.value })) .catch((error) => { console.error(`Failed to get secret ${secretName}: ${error}`); return { [secretName]: null }; }) ); const secretObjects = await Promise.all(secretPromises); return Object.assign({}, ...secretObjects); } export default getSecrets;
方案2:添加缓存过期机制(平衡性能与实时性)
如果不想每次请求都调用密钥库,可以设置缓存过期时间,超过时间后自动重新拉取:
import { Env_Keys } from "@/types/customType"; import { DefaultAzureCredential } from "@azure/identity"; import { SecretClient } from "@azure/keyvault-secrets"; export const dynamic = "force-dynamic"; const credential = new DefaultAzureCredential(); const vaultName = ""; const url = `https://${vaultName}.vault.azure.net`; const client = new SecretClient(url, credential); let secrets: Env_Keys | null = null; let lastFetchTime: number | null = null; // 设置缓存过期时间,比如5分钟(300000毫秒) const CACHE_TTL = 300000; async function getSecrets() { const now = Date.now(); // 如果缓存不存在,或者已过期,重新拉取 if (!secrets || !lastFetchTime || now - lastFetchTime > CACHE_TTL) { const secretNames = [ "Test", ]; const secretPromises = secretNames.map((secretName) => client .getSecret(secretName) .then((secret) => ({ [secretName]: secret.value })) .catch((error) => { console.error(`Failed to get secret ${secretName}: ${error}`); return { [secretName]: null }; }) ); const secretObjects = await Promise.all(secretPromises); secrets = Object.assign({}, ...secretObjects); lastFetchTime = now; } return secrets; } export default getSecrets;
验证修改
修改后重新部署或重启开发服务器,更新Azure密钥库中的Test密钥,再调用API就能获取到最新的值了。
内容的提问来源于stack exchange,提问作者Jagdish Padeliya
相关产品推荐
相关产品推荐

