Node.js中无法获取Promise返回的access_token及全局使用方案
问题原因
- 你当前导出的
getAccessToken是返回Promise的函数,不是最终的token值。在app.js中直接打印ac.getAccessToken输出的是函数本身,既没有执行函数,也没有处理Promise的异步返回,自然拿不到token值。 - firebase.js中自行调用
getAccessToken().then(...)的逻辑里,返回的access_token只在当前Promise链内部生效,既没有做持久缓存,也没有对外暴露,外部模块无法读取。 - Firebase的access_token默认有效期为1小时,仅在服务启动时获取一次就永久使用,运行一段时间后会因为token过期出现接口鉴权失败的问题,必须配套过期自动刷新逻辑。
实现方案(全局可用+自动刷新)
第一步:改造firebase.js,增加token缓存与自动刷新逻辑
替换原有firebase.js代码如下:
var {google} = require('googleapis'); var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging'; var SCOPES = [MESSAGING_SCOPE]; // 缓存token与过期时间 let cachedToken = null; let tokenExpireTime = 0; function getAccessToken() { return new Promise(function(resolve, reject) { const now = Date.now(); // 缓存的token距离过期还有5分钟以上时,直接返回缓存值 if (cachedToken && now < tokenExpireTime - 5 * 60 * 1000) { return resolve(cachedToken); } var key = require('./serviceAccountKey.json'); var jwtClient = new google.auth.JWT( key.client_email, null, key.private_key, SCOPES, null ); jwtClient.authorize(function(err, tokens) { if (err) { reject(err); return; } // 更新缓存 cachedToken = tokens.access_token; tokenExpireTime = tokens.expiry_date; resolve(cachedToken); }); }); } module.exports = getAccessToken;
第二步:改造app.js,启动时初始化token并全局挂载
替换原有app.js代码如下,确保服务启动前先完成第一次token拉取,启动后全项目可直接调用:
const express = require("express"); const getAccessToken = require('./firebase.js'); const app = express(); const port = process.env.PORT || 1111 ; async function startServer() { try { // 启动前先拉取初始token,校验账号配置正确性 const initToken = await getAccessToken(); console.log('初始access_token获取成功:', initToken); // 挂载到全局,全项目无需重复引入firebase.js即可调用 global.getFirebaseAccessToken = getAccessToken; app.listen(port, () => { console.log(`server up and running on ${port}`); }); } catch (err) { console.error('服务启动失败,access_token获取异常:', err); process.exit(1); } } startServer();
全局调用方式
项目内任意路由、业务文件中,不需要重复引入firebase模块,直接调用全局方法即可拿到当前有效的access_token,无需关心缓存、过期刷新逻辑:
// 任意业务文件示例 router.post('/send-firebase-push', async (req, res) => { try { // 直接获取最新有效token const accessToken = await global.getFirebaseAccessToken(); // 后续将accessToken放入请求Authorization头,调用FCM接口即可 res.send({code: 0, msg: '推送请求发送成功'}) } catch (err) { res.status(500).send({code: -1, msg: err.message}) } })
补充说明
- 不建议将固定token值直接存为全局变量,token过期后会自动失效,必须通过带缓存判断的方法获取,才能保证运行期间一直可用。
- 如果不想使用global挂载,也可以在需要使用token的文件中单独引入firebase.js的
getAccessToken方法,Node.js模块是单例模式,缓存的token在全项目中共享,效果和全局挂载一致。 - Promise类型的返回值必须通过
await或者.then()回调才能拿到最终结果,直接打印Promise函数本身无法获取内部resolve的值。
内容的提问来源于stack exchange,提问作者aasir khan
相关产品推荐
相关产品推荐

