Node.js通过Firebase向iOS发推送通知遇INVALID_ARGUMENT错误求助
iOS设备FCM推送报错BadDeviceToken的排查与解决
问题场景
我尝试通过Firebase从Node.js向iOS设备发送推送通知,操作流程如下:
- iOS端调用
await messaging().getAPNSToken();获取APNS Token - 将Token发送到后端,通过以下函数转换为FCM Token:
export const convertAPNSToFCMToken = async token => { const fcmMessage = { application: 'com.xxxx.xxxx', sandbox: false, apns_tokens: [token] } const options = { headers: { Authorization: `Bearer ${accessToken}`, access_token_auth: true } } try { const { data } = await axios.post('https://iid.googleapis.com/iid/v1:batchImport', fcmMessage, options) return data.results[0].registration_token } catch (error) { winston.error('Unable to send message to Firebase') winston.error(error) } }
- 使用转换后的FCM Token调用发送通知方法:
const sendFCMMessage = async ({ accessToken = '', fcmToken = '', title = '', body = '' }) => { try { const fcmMessage = JSON.stringify({ message: { data: {}, notification: { title: title, body: body }, token: fcmToken } }) const options = { hostname: 'fcm.googleapis.com', path: `/v1/projects/${process.env.GOOGLE_SERVICE_ACCOUNT_PROJECT_ID}/messages:send`, method: 'POST', headers: { Authorization: `Bearer ${accessToken}` } } const request = https.request(options, resp => { resp.setEncoding('utf8') resp.on('data', data => { winston.info('Message sent to Firebase for delivery, response:') winston.info(data) }) }) request.on('error', err => { winston.error('Unable to send message to Firebase') winston.error(err) }) request.write(fcmMessage) request.end() } catch (e) { winston.error(e.message) return Promise.reject(e) } }
但收到如下错误响应:
{ "error": { "code": 400, "message": "Request contains an invalid argument.", "status": "INVALID_ARGUMENT", "details": [ { "@type": "type.googleapis.com/google.firebase.fcm.v1.FcmError", "errorCode": "INVALID_ARGUMENT" }, { "@type": "type.googleapis.com/google.firebase.fcm.v1.ApnsError", "statusCode": 400, "reason": "BadDeviceToken" } ] } }
备注:已在Firebase控制台配置好所有必要的认证信息。
排查与解决步骤
1. 核对APNS环境与Token匹配
BadDeviceToken最常见的原因是环境不匹配:
- 如果你的iOS设备使用的是测试包(Xcode调试、AdHoc),
convertAPNSToFCMToken函数中的sandbox参数必须设为true;生产包才用false。 - 验证APNS Token格式:确保iOS端返回的是64位十六进制字符串,没有被截断或修改。
2. 检查FCM Token转换参数
- 确认
application字段的Bundle ID与Firebase控制台注册的iOS应用完全一致,大小写敏感。 - 验证
accessToken权限:转换Token所用的access token需包含firebase.messaging权限,建议使用Firebase服务账号生成的token,而非临时用户token。
3. 简化推送请求(推荐使用Firebase Admin SDK)
手动构造HTTP请求容易出现格式或权限问题,改用Firebase Admin SDK可自动处理Token转换和请求格式:
步骤1:安装依赖
npm install firebase-admin
步骤2:初始化Admin SDK
const admin = require('firebase-admin'); const serviceAccount = require('./path/to/your-service-account-key.json'); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), });
步骤3:直接发送推送(无需手动转换Token)
const sendPushNotification = async (apnsToken, title, body) => { const message = { apns: { payload: { aps: { alert: { title: title, body: body, }, sound: 'default' }, }, headers: { 'apns-push-type': 'alert', 'apns-expiration': '0', 'apns-priority': '5', }, }, token: apnsToken, }; try { const response = await admin.messaging().send(message); console.log('推送发送成功:', response); return response; } catch (error) { console.error('推送发送失败:', error); throw error; } };
4. 设备端与证书校验
- 确认iOS设备已开启应用的推送权限(设置→通知→对应应用)。
- 检查Firebase控制台的APNs认证信息:证书/密钥是否对应正确环境(开发/生产),且未过期。
内容的提问来源于stack exchange,提问作者Pila
相关产品推荐
相关产品推荐

