Express中process.env.CLIENT_ID函数内可用,全局定义却为undefined
问题
使用OAuth对接Google API,通过.env文件存储敏感变量并通过.gitignore隐藏。遇到以下问题:
- 将
CLIENT_ID = process.env.CLIENT_ID定义为函数外的全局变量时,打印结果为undefined - 但在函数内部定义相同变量时,可正常获取.env中的值
项目采用MVC架构,已在server.js中配置:
require('dotenv').config({path: './config/.env'})
可正常运行的控制器代码(变量在函数内定义)
const passport = require('passport') const validator = require('validator') const User = require('../models/User') const Company = require('../models/Company') const { google } = require('googleapis'); const { OAuth2Client } = require('google-auth-library'); const axios = require('axios'); const auth = require('../middleware/auth'); const dayjs = require('dayjs') exports.googleAuthCode = (req, res) => { let CLIENT_ID = process.env.CLIENT_ID; let CLIENT_SECRET = process.env.CLIENT_SECRET; let REDIRECT_URL = process.env.REDIRECT_URL; const SCOPES = 'https://www.googleapis.com/auth/calendar'; const oAuth2Client = new google.auth.OAuth2( CLIENT_ID, CLIENT_SECRET, REDIRECT_URL, ); console.log('running googleAuthCode') console.log('process.env.CLIENT_ID ', process.env.CLIENT_ID) console.log('process.env.CLIENT_SECRET ', process.env.CLIENT_SECRET) console.log('process.env.REDIRECT_URL ', process.env.REDIRECT_URL) console.log('CLIENT_ID ', CLIENT_ID) console.log('CLIENT_SECRET ', CLIENT_SECRET) console.log('REDIRECT_URL ', REDIRECT_URL) const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: SCOPES, }); console.log('authURL: ',authUrl) res.redirect(authUrl); }
无法运行的控制器代码(变量在全局定义)
const passport = require('passport') const validator = require('validator') const User = require('../models/User') const Company = require('../models/Company') const { google } = require('googleapis'); const { OAuth2Client } = require('google-auth-library'); const axios = require('axios'); const auth = require('../middleware/auth'); const dayjs = require('dayjs') let CLIENT_ID = process.env.CLIENT_ID; let CLIENT_SECRET = process.env.CLIENT_SECRET; let REDIRECT_URL = process.env.REDIRECT_URL; const SCOPES = 'https://www.googleapis.com/auth/calendar'; const oAuth2Client = new google.auth.OAuth2( CLIENT_ID, CLIENT_SECRET, REDIRECT_URL, ); exports.googleAuthCode = (req, res) => { console.log('running googleAuthCode') console.log('process.env.CLIENT_ID ', process.env.CLIENT_ID) console.log('process.env.CLIENT_SECRET ', process.env.CLIENT_SECRET) console.log('process.env.REDIRECT_URL ', process.env.REDIRECT_URL) console.log('CLIENT_ID ', CLIENT_ID) console.log('CLIENT_SECRET ', CLIENT_SECRET) console.log('REDIRECT_URL ', REDIRECT_URL) const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: SCOPES, }); console.log('authURL: ',authUrl) res.redirect(authUrl); }
希望实现将这些环境变量作为全局变量正常使用。
解决方案
问题核心是模块加载顺序:控制器模块在dotenv完成.env文件加载之前就被导入了,导致全局变量初始化时process.env还没有对应的值。
方案1:确保dotenv是第一个被加载的模块
修改server.js,把dotenv的配置放在所有其他require语句的最前面:
// server.js 第一行就加载dotenv require('dotenv').config({path: './config/.env'}); // 然后再导入其他模块 const express = require('express'); const yourController = require('./path/to/your/controller'); // ...其他代码
这样所有后续导入的模块(包括你的控制器)在初始化时,process.env已经包含了.env中的变量。
方案2:延迟变量初始化(用函数封装)
如果无法调整加载顺序,可以把全局变量的获取逻辑封装成函数,延迟到请求处理时再执行:
const passport = require('passport') const validator = require('validator') const User = require('../models/User') const Company = require('../models/Company') const { google } = require('googleapis'); const { OAuth2Client } = require('google-auth-library'); const axios = require('axios'); const auth = require('../middleware/auth'); const dayjs = require('dayjs') const SCOPES = 'https://www.googleapis.com/auth/calendar'; // 封装成函数,每次调用时才获取环境变量并创建客户端 const getOAuth2Client = () => { const CLIENT_ID = process.env.CLIENT_ID; const CLIENT_SECRET = process.env.CLIENT_SECRET; const REDIRECT_URL = process.env.REDIRECT_URL; return new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); } exports.googleAuthCode = (req, res) => { const oAuth2Client = getOAuth2Client(); console.log('running googleAuthCode') console.log('process.env.CLIENT_ID ', process.env.CLIENT_ID) console.log('CLIENT_ID ', process.env.CLIENT_ID) const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: SCOPES, }); console.log('authURL: ',authUrl) res.redirect(authUrl); }
方案3:单独封装环境变量模块
创建一个专门的配置模块,比如config/env.js:
// config/env.js require('dotenv').config({path: './config/.env'}); module.exports = { CLIENT_ID: process.env.CLIENT_ID, CLIENT_SECRET: process.env.CLIENT_SECRET, REDIRECT_URL: process.env.REDIRECT_URL };
然后在控制器中导入这个模块(确保这个配置模块在其他模块之前被加载,或者在server.js中先导入它):
const { CLIENT_ID, CLIENT_SECRET, REDIRECT_URL } = require('../config/env'); // ...其他代码
内容的提问来源于stack exchange,提问作者acodeaday
相关产品推荐
相关产品推荐

