Firebase Functions本地调试报错:Cannot read properties of undefined (reading 'toString')
问题描述
我正在调试用于触发通知的Firebase Functions,通过Firebase CLI执行firebase emulators:start命令启动模拟器。但调用localhost:5001上的函数时,出现错误Cannot read properties of undefined (reading 'toString'),终端也输出对应的TypeError堆栈信息。
调用的本地URL为:http://localhost:5001/projectname-83750/us-central1/sendNotificationOnFighterDataChangeToFans-0
函数代码如下:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp({ credential: admin.credential.applicationDefault(), databaseURL: "https://console.firebase.google.com/project/projectname", }); exports.sendNotificationOnFighterDataChangeToFans = functions.firestore .document("users/{userId}") .onUpdate(async (change, context) => { const before = change.before.data(); // Data before the change const after = change.after.data(); // Data after the change // Check if userName changed if (before.weightClass !== after.weightClass) { const userId = context.params.userId; const fighterSnapshot = await admin .firestore() .collection("users") .doc(userId) .get(); const fighterData = fighterSnapshot.data(); if (fighterData && fighterData.route === "fighter") { const followers = fighterData.followers || []; const fanPromises = followers.map(async (followerId) => { const fanSnapshot = await admin .firestore() .collection("users") .doc(followerId) .get(); const fanData = fanSnapshot.data(); if (fanData && fanData.route === "fan" && fanData.deviceToken) { const notification = { token: fanData.deviceToken, notification: { title: "UserName Changed", body: `Your userName has been changed to ${after.userName}`, }, }; try { await admin.messaging().send(notification); console.log("Notification sent successfully"); } catch (error) { console.error("Error sending notification:", error); } } }); await Promise.all(fanPromises); } } });
问题分析与修复步骤
1. DatabaseURL配置错误
admin.initializeApp中的databaseURL填写错误,应该使用Firebase Realtime Database的官方URL(格式为https://<project-id>.firebaseio.com),而非控制台页面链接。错误的URL会导致Admin SDK初始化异常,进而触发toString相关的TypeError。
修复代码:
admin.initializeApp({ credential: admin.credential.applicationDefault(), databaseURL: "https://projectname-83750.firebaseio.com", // 替换为你的项目实际Realtime Database地址 });
2. 错误的函数调用方式
你通过HTTP URL直接调用了Firestore的onUpdate触发器函数,这不符合触发器的运行逻辑。Firestore触发器函数只能由对应文档的更新事件触发,无法通过HTTP请求直接调用。
正确测试方式:
- 在Firestore模拟器中修改
users集合下任意文档的weightClass字段,自动触发函数执行; - 若需通过HTTP测试通知逻辑,可单独编写HTTP触发器函数,或使用Firebase Emulator Suite的UI模拟Firestore事件。
3. 冗余的文档读取操作
onUpdate触发器已通过change.before和change.after提供了文档的前后数据,无需再次读取users/{userId}文档,这会增加不必要的资源开销。可以直接使用after.data()获取最新数据:
优化代码片段:
// 替换原有的fighterSnapshot和fighterData读取逻辑 const fighterData = after.data(); if (fighterData && fighterData.route === "fighter") { // 后续逻辑保持不变 }
4. 通知内容与判断逻辑不匹配
判断条件是检查weightClass是否变化,但通知标题和内容却标注为"UserName Changed",逻辑与内容不一致,需修正:
notification: { title: "Weight Class Updated", body: `The weight class of your followed fighter has changed to ${after.weightClass}`, },
内容的提问来源于stack exchange,提问作者EnCoder2000

