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

Next.js启动服务前需访问环境变量,如何在next命令前执行vault脚本?

解决方案

方案1:修改package.json脚本串行执行

npm/yarn/pnpm默认会按&&连接的命令串行执行,前一个命令退出码为0才会执行后续命令,直接修改scripts配置即可:

{
  "scripts": {
    "fetch:secrets": "node fetch-vault-secrets.js",
    "dev": "npm run fetch:secrets && next dev",
    "build": "npm run fetch:secrets && next build",
    "start": "next start"
  }
}

注意:要确保fetch-vault-secrets.js拉取完密钥、写入.env文件后才主动退出,不要留未处理的异步逻辑就提前退出,否则会出现密钥还没写完就启动Next.js的问题。如果脚本内是异步请求Vault,要把逻辑包在async函数里,执行成功调用process.exit(0),出错就调用process.exit(1)终止后续流程。

fetch-vault-secrets.js 参考实现

const fs = require('fs/promises')
const axios = require('axios')

async function main() {
  // 从环境变量读取Vault认证信息
  const { VAULT_ADDR, ROLE_ID, VAULT_SECRET_ID } = process.env
  if (!VAULT_ADDR || !ROLE_ID || !VAULT_SECRET_ID) {
    console.error('缺少Vault认证必要环境变量')
    process.exit(1)
  }

  try {
    // 登录Vault获取token
    const loginRes = await axios.post(`${VAULT_ADDR}/v1/auth/approle/login`, {
      role_id: ROLE_ID,
      secret_id: VAULT_SECRET_ID
    })
    const vaultToken = loginRes.data.auth.client_token

    // 拉取对应路径的密钥
    const secretRes = await axios.get(`${VAULT_ADDR}/v1/你的密钥存储路径`, {
      headers: { 'X-Vault-Token': vaultToken }
    })
    const secrets = secretRes.data.data

    // 写入.env文件
    const envContent = Object.entries(secrets).map(([k, v]) => `${k}=${v}`).join('\n')
    await fs.writeFile('.env', envContent, 'utf8')
    process.exit(0)
  } catch (err) {
    console.error('拉取Vault密钥失败', err.message)
    process.exit(1)
  }
}

main()

方案2:使用pre钩子自动执行前置脚本

npm/yarn/pnpm都支持pre脚本钩子,命名为pre[脚本名]的脚本会自动在对应脚本执行前运行,不需要手动加&&:

{
  "scripts": {
    "fetch:secrets": "node fetch-vault-secrets.js",
    "predev": "npm run fetch:secrets",
    "prebuild": "npm run fetch:secrets",
    "dev": "next dev",
    "build": "next build"
  }
}

这种方式的好处是不管你怎么启动dev和build命令,都会自动先跑密钥拉取逻辑,不会出现漏执行的情况。

方案3:Next.js配置层注入(适合密钥不落地场景)

如果你不想把密钥落地到本地.env文件,可以直接在next.config.js里引入密钥拉取逻辑,Next.js启动时会优先加载这个配置文件:

// next.config.js
const fetchVaultSecrets = require('./fetch-vault-secrets')

module.exports = async () => {
  // 先拉取Vault密钥,直接注入到process.env
  const secrets = await fetchVaultSecrets()
  Object.assign(process.env, secrets)

  return {
    // 你的其他Next.js配置
    reactStrictMode: true,
  }
}

注意:这种方式仅在Next.js的Node.js运行时生效,浏览器端的环境变量还是需要按照Next.js规则,以NEXT_PUBLIC_开头才会被注入到客户端。

额外注意事项

  • 存放VAULT_SECRET_ID和ROLE_ID的文件不要提交到Git仓库,要加入.gitignore
  • 本地开发时这两个ID可以存放到本地的.env.local文件中,Next.js会自动加载这个文件的变量给fetch-vault-secrets.js使用
  • 生产环境的ROLE_ID和SECRET_ID建议通过部署平台的环境变量能力注入,不要落地到磁盘

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:54:03