如何在React与Node.js应用中跨框架统一读取环境变量?
我正在开发一个monorepo TypeScript SDK,其中某个函数需要用户设置API_KEY和SECRET作为环境变量,通过process.env.API_KEY和process.env.SECRET读取后传入第三方SDK用于授权,代码实现如下:
// @ts-ignore if (!process.env.API_KEY || !process.env.SECRET) { throw new Error('Please provide your API_KEY and SECRET as env variables'); } // @ts-ignore const authorization = 'Basic ' + Buffer.from(process.env.API_KEY + ':' + process.env.SECRET).toString('base64'); const res = thirdPartySDK.function({ url, headers:{ authorization } });
这个实现在Node.js应用中运行正常,但在React应用中会抛出环境变量未设置的错误——因为React要求环境变量必须以REACT_APP_为前缀,而当前实现没有使用前缀。
我的核心需求是:以独立于应用框架的方式读取无前缀的环境变量,不管用户用React、Vite还是其他框架,都能让SDK直接读取API_KEY和SECRET,不需要适配不同框架的前缀规则。
我自己想了几个方案,但都不满意:
- 要求用户设置无前缀的环境变量,但在React里操作繁琐,也不确定是否可行;
- 放弃读取环境变量,让用户直接把密钥传入函数,但用户需要信任SDK,我不太偏好这个方案;
- 分别适配React、Node.js等不同框架的环境变量格式,但还要考虑Vite这类框架,太繁琐,希望能找到统一的无前缀读取方式。
解决方案
1. 内部自动适配主流框架前缀
在SDK里加一层兼容逻辑,自动检测并读取不同框架前缀的环境变量,把它们映射到无前缀的名称上。这样用户不管设置API_KEY、REACT_APP_API_KEY还是VITE_API_KEY,SDK都能拿到值:
// 定义主流框架的环境变量前缀 const envPrefixes = ['', 'REACT_APP_', 'VITE_']; // 封装读取环境变量的工具函数 function getEnv(key: string): string | undefined { for (const prefix of envPrefixes) { const fullKey = `${prefix}${key}`; if (process.env[fullKey]) { return process.env[fullKey]; } } return undefined; } // 使用工具函数替代直接读取process.env const apiKey = getEnv('API_KEY'); const secret = getEnv('SECRET'); if (!apiKey || !secret) { throw new Error('Please provide your API_KEY and SECRET as env variables'); } const authorization = 'Basic ' + Buffer.from(`${apiKey}:${secret}`).toString('base64'); const res = thirdPartySDK.function({ url, headers:{ authorization } });
这种方式完全不需要用户额外操作,SDK自动兼容主流框架,用户按自己框架的习惯设置变量就行。
2. 支持独立配置文件读取
让用户在项目根目录创建一个专属配置文件(比如.env.sdk),在里面设置无前缀的API_KEY和SECRET,SDK直接读取这个文件。可以用dotenv包实现:
首先给SDK添加dotenv依赖,然后编写读取逻辑:
import dotenv from 'dotenv'; import path from 'path'; // 加载项目根目录下的.env.sdk文件 dotenv.config({ path: path.resolve(process.cwd(), '.env.sdk') }); // 现在可以直接读取无前缀的变量 const apiKey = process.env.API_KEY; const secret = process.env.SECRET; if (!apiKey || !secret) { throw new Error('Please provide your API_KEY and SECRET in .env.sdk or as env variables'); } // 后续授权逻辑不变 const authorization = 'Basic ' + Buffer.from(`${apiKey}:${secret}`).toString('base64'); const res = thirdPartySDK.function({ url, headers:{ authorization } });
这种方式给用户一个统一的配置入口,不管用什么框架,只需要维护.env.sdk就行,彻底避开框架前缀限制。
3. 环境变量+显式传入兼容方案
虽然你不偏好显式传密钥,但可以做个折中:优先读环境变量,读不到再允许用户通过函数参数传入。这样既保留了环境变量的安全性,又给用户留了灵活选择的空间:
type SDKOptions = { apiKey?: string; secret?: string; }; function yourSDKFunction(url: string, options?: SDKOptions) { // 优先级:传入的参数 > 环境变量 const apiKey = options?.apiKey || process.env.API_KEY; const secret = options?.secret || process.env.SECRET; if (!apiKey || !secret) { throw new Error('Please provide your API_KEY and SECRET either as env variables or via function options'); } const authorization = 'Basic ' + Buffer.from(`${apiKey}:${secret}`).toString('base64'); return thirdPartySDK.function({ url, headers:{ authorization } }); }
用户如果觉得框架前缀麻烦,就可以选择显式传入;如果习惯用环境变量,也能正常使用。
内容的提问来源于stack exchange,提问作者NewToCode

