Firebase Admin NodeJS SDK发送FCM消息遇无效令牌超时求助
解决Firebase Admin SDK发送FCM到失效令牌时Lambda超时问题
核心原因
失效的FCM令牌会导致admin.messaging().send()方法在Lambda环境下底层HTTP请求卡住,无法触发Promise的resolve/reject,常规try-catch无法捕获,最终导致Lambda超时。
解决方案
1. 给FCM发送方法添加手动超时包装
通过Promise.race将send请求和超时Promise绑定,强制在指定时间内结束请求,避免无限挂起:
const admin = require('firebase-admin'); // 包装send方法,添加超时逻辑 const sendFcmWithTimeout = async (message, timeoutMs = 10000) => { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('FCM请求超时')), timeoutMs); }); // 竞速执行send请求和超时逻辑 return Promise.race([admin.messaging().send(message), timeoutPromise]); }; // 业务代码中调用 exports.handler = async (event) => { const msg = { token: '失效的FCM令牌', notification: { title: '测试消息', body: '内容' } }; try { await sendFcmWithTimeout(msg); return { statusCode: 200, body: '发送成功' }; } catch (error) { console.error('FCM处理失败:', error.message); // 针对超时或令牌错误做后续处理 if (error.message.includes('超时')) { // 可标记该令牌疑似失效,后续验证 } return { statusCode: 500, body: '发送失败' }; } };
2. 发送前提前验证令牌有效性
利用admin.messaging().validateToken()提前检查令牌状态,直接过滤失效令牌,避免进入send流程:
exports.handler = async (event) => { const targetToken = '待验证的FCM令牌'; const msg = { token: targetToken, notification: { title: '测试消息', body: '内容' } }; try { // 先验证令牌有效性 await admin.messaging().validateToken(targetToken); // 验证通过再发送 await admin.messaging().send(msg); return { statusCode: 200, body: '发送成功' }; } catch (error) { // 处理令牌失效类错误 if (['messaging/invalid-registration-token', 'messaging/registration-token-not-registered'].includes(error.code)) { console.log('令牌已失效,移除:', targetToken); // 这里更新数据库,删除该失效令牌,避免后续重复发送 } else { console.error('发送错误:', error); } return { statusCode: 500, body: '处理失败' }; } };
3. 配置SDK的HTTP客户端超时
初始化Firebase Admin SDK时,设置HTTP/HTTPS客户端的超时时间,从底层限制请求时长:
const admin = require('firebase-admin'); const http = require('http'); const https = require('https'); // 创建带超时配置的HTTP/HTTPS代理 const httpAgent = new http.Agent({ keepAlive: true, timeout: 5000 // 5秒超时 }); const httpsAgent = new https.Agent({ keepAlive: true, timeout: 5000 }); // 初始化SDK时传入代理配置 admin.initializeApp({ credential: admin.credential.applicationDefault(), httpAgent: httpAgent, httpsAgent: httpsAgent });
关键注意事项
- 当捕获到
messaging/registration-token-not-registered错误时,一定要从数据库中移除该令牌,避免后续重复触发相同问题。 - 超时时间建议设置为10秒以内,适配Lambda的30秒超时上限,预留足够时间处理其他业务逻辑。
内容的提问来源于stack exchange,提问作者SandDev
相关产品推荐
相关产品推荐

