Ionic+Socket.io聊天话题创建时消息重复发送问题求助
看起来你的核心问题是Socket.io事件监听器重复绑定,再加上页面生命周期未清理监听器,导致多次触发消息发送逻辑。结合你的代码和场景,我来一步步帮你排查解决:
1. 移除累积的Socket事件监听器
每次进入添加话题页面时,你在constructor里执行this.socket.on('add-message', ...)——但Socket.io的on方法是添加监听器,不是替换。这意味着你每进入一次页面,就会多绑定一个add-message的处理函数。当服务端发送add-message事件时,所有绑定的监听器都会执行,自然会重复调用this.chatService.sendMsg(data),导致消息重复发送。
修复方案:在页面销毁时移除监听器
修改你的添加话题页面代码,实现OnDestroy接口,在页面销毁时移除对应的Socket监听器:
import { Component, OnDestroy } from '@angular/core'; // 引入OnDestroy export class AddSalonPage implements OnDestroy { private addMessageListener: any; // 保存监听器引用,方便后续移除 constructor(public navCtrl: NavController, public navParams: NavParams, public chatService: ChatService, private socket: Socket, public events: Events) { // 将监听器逻辑赋值给变量 this.addMessageListener = (data) => { console.log("recu la reponse = " + JSON.stringify(data)); this.chatService.sendMsg(data); }; // 绑定监听器 this.socket.on('add-message', this.addMessageListener); this.chatService.getUserInfo() .then((res) => { this.user = res }); } // 页面销毁时移除监听器 ngOnDestroy() { if (this.addMessageListener) { this.socket.off('add-message', this.addMessageListener); } } // 你的话题提交逻辑 submitSalon(newSalon, newMsg) { this.chatService.sendSalon(newSalon, newMsg) .then(() => { console.log("Message envoyé et contenu : " + JSON.stringify(newSalon)); // 建议用JSON.stringify看完整内容 this.navCtrl.setRoot(ChatListPage); }) } }
2. 优化客户端-服务端的消息流程
从你的代码看,当前流程是:
客户端发送
add-salon→ 服务端保存话题后,socket.emit('add-message', message)给客户端 → 客户端收到后调用sendMsg,再次发送add-message到服务端保存
这个流程本身是合理的,但之前因为监听器重复,导致这一步被多次触发。修复监听器问题后,这个流程就只会执行一次。
另外,建议你在服务端的add-salon逻辑中,直接完成消息的保存,避免客户端二次发送——这样能减少一次网络请求,也降低出错概率:
// 服务端add-salon逻辑优化 socket.on('add-salon', (envoi) => { salon = envoi.salon; message = envoi.message; salon._id = new ObjectID(); db.collection("chatSalons", function(err, collection) { collection.save(salon, function(err, result) { if(err) { console.log('parse : err2 ' + err); return; } message.chatId = salon._id; // 直接用已保存的salon._id,无需重新创建ObjectID message._id = new ObjectID(); // 直接保存消息到数据库 db.collection("chatMsgs", function(err, msgCollection) { msgCollection.save(message, function(err, msgResult) { if (err) {console.log('parse :err3'+err); return;} // 只需要通知客户端消息已保存,不需要让客户端再发一次 socket.emit('message-saved', message); io.emit('salon-received', {text: salon.title, from: salon.userId, created: new Date()}); }); }); }); }); });
对应的客户端可以移除add-message的监听器,直接在sendSalon后处理页面跳转即可,不需要再触发sendMsg。
3. 清理ChatService中的冗余异步逻辑
你的ChatService里用了多层setTimeout和Promise,这些随机延迟不仅可能导致时序问题,还会增加调试难度。如果没有特殊需求,建议简化:
sendSalon(salon: ChatSalon, message: ChatMessage) { console.log("chat service sendSalon = " + JSON.stringify(salon)); return this.mockNewSalon(salon, message); } mockNewSalon(salon, message) { console.log(salon); console.log("contenu message avant envoi vers le serveur = " + JSON.stringify(message)); this.socket.emit('add-salon', {salon, message}); return Promise.resolve(); // 返回Promise保持接口一致性 } // 如果优化了服务端流程,sendMsg可以只用于普通聊天消息发送 sendMsg(msg: ChatMessage) { console.log("chat service sendMsg = " + JSON.stringify(msg)); return this.mockNewMsg(msg); } mockNewMsg(msg) { this.socket.emit('add-message', msg); return Promise.resolve(); }
验证问题是否解决
完成以上修改后,你可以测试以下场景:
- 创建新话题,检查首条消息是否只发送一次
- 多次进入/离开添加话题页面,检查是否会无触发消息发送
- 跨设备测试,确认之前修复的跨设备重复问题依然正常
内容的提问来源于stack exchange,提问作者user7195420

