Flutter调用Firebase可调用函数发送FCM通知时出现400错误:参数无效(sentBy/sentTo为null)
Flutter调用Firebase可调用函数发送FCM通知时出现400错误:参数无效(sentBy/sentTo为null)
看起来你遇到的问题是函数端检测到sentBy或sentTo为null,但Flutter端明明已经传递了参数且用户已登录。咱们一步步排查解决:
首先,排查sentBy为null的可能原因
context.auth?.uid为null通常意味着Firebase可调用函数没有获取到用户的认证上下文。虽然HttpsCallable默认会自动带上当前登录用户的身份信息,但还是有几个点需要确认:
- 检查你的Firebase可调用函数是否启用了身份验证:默认情况下,可调用函数要求用户必须登录,但如果你的函数配置了宽松的安全规则(比如允许未认证访问),
context.auth会是null。你可以在函数代码里加一行调试日志,看看context.auth的具体内容:console.log('Context auth details:', context.auth); - 确认Flutter端的用户确实处于登录状态:虽然你判断了
currentUser != null,但可以额外打印当前用户的UID,确保它不为空:print("Current logged-in user UID: ${currentUser.uid}");
然后,排查sentTo为null的问题
你说sentTo是设备Token,但函数端接收不到,可能的原因:
- 检查Flutter端传参的键名是否完全匹配:你的代码里传的是
"sentTo",函数里取的是data.sentTo,键名是对的,但可以在函数里打印收到的data对象,确认是否真的收到了这个参数:console.log('Received request data:', data); - 确认Flutter端的
sentTo变量确实不为空:你代码里的打印是print('senTo '+sentTo);——这里有个拼写错误(senTo少了一个t),虽然变量本身是sentTo,但建议修正打印语句,确保你看到的是真实的变量值:print('sentTo value: $sentTo');
还有一个隐藏问题:FCM消息的payload未定义
你的函数代码里直接调用了admin.messaging.sendToDevice(sentTo, payload),但payload变量根本没定义!这会导致后续发送通知时抛出错误,即使前面的参数检查通过了。你需要先定义FCM的消息payload,比如:
const payload = { notification: { title: "有人戳了你!", body: message, sound: "default" // 让通知有提示音 }, data: { // 可选:传递额外数据给客户端 senderUid: sentBy, timestamp: currentTime.toDate().toString() } };
修改后的完整函数代码参考
const functions = require("firebase-functions"); const admin = require("firebase-admin"); //admin sdk module.exports = async (data,context) => { // 调试日志,帮助定位问题 console.log('Received data:', data); console.log('Context auth:', context.auth); const sentBy = context.auth?.uid; // 发送者UID const sentTo = data.sentTo; // 接收者的设备Token const message = data.message || "Seni dürttü!"; const currentTime = admin.firestore.Timestamp.now(); if (!sentBy || !sentTo) { throw new functions.https.HttpsError( "invalid-argument", `发送者和接收者信息不能为空。sentBy: ${sentBy}, sentTo: ${sentTo}` ); } // 定义FCM通知内容 const payload = { notification: { title: "新的戳一下通知", body: message, sound: "default" }, data: { sentBy: sentBy, timestamp: currentTime.toDate().toString() } }; try { const response = await admin.messaging.sendToDevice(sentTo, payload); console.log('通知发送成功:', response); return { success: true, message: "通知已发送" }; } catch (error) { console.error('发送通知失败:', error); throw new functions.https.HttpsError("internal", "发送通知失败,请稍后重试", error); } };
修改后的Flutter端代码参考
Future<void> sendPokeNotification(String sentTo) async { try { final HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('sendPoke'); print('sentTo: $sentTo'); // 确认设备Token不为空 final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { throw Exception("用户未登录"); } print("当前登录用户UID: ${currentUser.uid}"); // 确认用户已登录 final idToken = await currentUser.getIdToken(); print("用户Token: $idToken"); final response = await callable.call<String, dynamic>({ "sentTo": sentTo, "message": 'Hi, i poked you!', }); print('函数响应: ${response.data}'); } catch (e) { print('发送戳一下通知错误: $e'); } }
按照上面的步骤排查和修改后,应该能解决参数为null的问题,同时修复FCM发送的隐藏错误。记得部署更新后的函数,然后测试看看调试日志里的内容,这样能更精准地定位问题。
备注:内容来源于stack exchange,提问作者Yasin G.
相关产品推荐
相关产品推荐

