Node.js中Firebase Admin的update方法触发多次回调如何解决
问题根源
ref.update() 本身是写操作方法,返回的Promise只会在写入成功/失败时触发一次resolve或reject,不存在自身多次触发回调的设计。
你遇到的重复回调、应用崩溃,本质是之前给当前ref或者它的上级父路径绑定过on()类的持续监听事件没有解绑:只要绑定了这类持续监听,对应路径下任何数据变动都会自动触发监听回调,如果你在这些回调里写了res.send()这类Express中只能执行一次的响应逻辑,就会触发ERR_HTTP_HEADERS_SENT报错(同一个请求重复发送响应头),直接导致应用崩溃。
之前读数据用once()能解决问题,本质是once()触发一次后会自动解绑监听,不会留下长期生效的监听器。
解决步骤
按优先级处理即可彻底解决:
- 清理遗留的无效持续监听
全局搜索项目中users/new_users路径、以及它的所有父路径(比如根路径下的users),找到所有通过ref.on('value'/'child_added'/'child_changed'...)绑定的监听:- 不需要长期生效的临时监听,逻辑执行完立刻调用
ref.off(对应事件名, 绑定的回调函数)主动解绑 - 需要长期保留的全局监听,回调内绝对不能写
res.send()这类和单次请求绑定的响应逻辑,只放数据同步、本地状态更新这类允许重复执行的代码
- 不需要长期生效的临时监听,逻辑执行完立刻调用
- 给接口加防重入兜底
就算有漏处理的异常触发,加个简单标记位就能避免重复发响应导致崩溃,改造后的接口代码如下:
app.get('/set-client', (req, res) => { // 标记响应是否已经发送 let responded = false; const ref = db.ref(`users/new_users`) ref.update({ 'client': uid_client}).then(function(){ if (responded) return; responded = true; console.log("Data saved successfully."); res.status(200).send("successful") }).catch(function(error) { if (responded) return; responded = true; console.log("Data could not be saved." + error); res.status(201).send("failed") }); });
别浪费时间找update配套的once方法,update不是事件订阅方法,本身就只执行一次,问题100%出在遗留的未解绑监听上。
内容的提问来源于stack exchange,提问作者Cesar Lopes
相关产品推荐
相关产品推荐

