You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQTT.js持久会话订阅者断开重连后收到QoS 2重复消息问题

问题原因

核心问题是MQTT协议中QoS 2的「恰好一次」交付是建立在消费端正确向broker发送确认报文的基础上,你当前的订阅端代码缺少手动确认逻辑,默认的自动确认逻辑存在时序漏洞:

  • MQTT.js默认开启autoAck,收到消息后会立刻自动向broker发送确认报文,但如果报文在网络传输过程中丢失、或客户端刚收到消息还没来得及发出确认就断开连接,broker会判定该消息未被成功消费,在你下次重连持久会话时就会重新推送。
  • 你当前的message事件回调参数写法不符合MQTT.js的标准定义,缺少后续手动确认必须的packet对象参数。
修复方案

修改subscriber.js代码,核心改动两点:连接配置开启手动确认、消息处理完成后手动触发确认:

const mqtt = require("mqtt");

const client = mqtt.connect("mqtt://localhost", {
  port: 1883,
  clean: false,
  clientId: "mqttjs_1",
  // 开启手动确认,关闭自动确认
  manualAcks: true
});

client.on("connect", () => {
  client.subscribe("Weather", { qos: 2 });
});

// 修正回调参数:顺序为 topic, 消息 payload, 报文对象
client.on("message", (topic, message, packet) => {
  const context = message.toString();
  console.log(context);
  // 处理完成后手动发送确认,告知broker该消息已消费
  client.ack(packet);
});
补充注意点
  • 如果你使用的是MQTT.js 3.x版本,配置项改为autoAck: false即可,手动确认逻辑保持一致。
  • 发布端代码中设置了clean: false但使用随机生成的clientId,会导致broker中积累大量无用的持久会话,如果你不需要发布端的持久会话能力,可将发布端的clean改为true减少broker资源占用。

内容的提问来源于stack exchange,提问作者Niccolò Fant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 07:42:02