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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:19:58