MQTT over WebSocket是将MQTT报文封装于WebSocket帧中传输的方案,使浏览器能通过ws/wss协议直连MQTT Broker,解决其无法原生支持TCP连接的限制。

浏览器不能直接连 MQTT Broker,因为 MQTT 基于 TCP,而 HTML/JavaScript 运行在沙箱环境里,只允许发起 HTTP 或 WebSocket 请求。所以「HTML 仪表盘接入 MQTT」本质是:用 WebSocket 封装 MQTT 报文,走 MQTT over WebSocket 协议,前端通过 JS 客户端(如 paho-mqtt 或 mqtt.js)建立连接。
为什么浏览器里不能直接用 mqtt:// 协议
浏览器会直接拦截 mqtt://、tcp:// 这类非 HTTP/HTTPS/WebSocket 的协议;调用 net.Socket 或原生 TCP API 会报 SecurityError 或直接不可用。这不是权限问题,是浏览器安全模型的硬性限制。
常见错误现象:Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss',或者控制台完全没日志、onConnect 回调不触发——大概率是 Broker 没开 WebSocket 监听端口,或前端连错了地址。
- Broker 必须显式启用 WebSocket 支持(比如 Mosquitto 需配置
listener 8080+protocol websockets;EMQX 默认开启8083ws 端口) - 前端 URL 必须以
ws://或wss://开头,不能写mqtt://或省略协议 - 若用 Nginx 反向代理 WebSocket,需透传
Upgrade和Connection头,否则连接会在 101 切换阶段失败
paho-mqtt 连接时必设的三个参数
paho-mqtt 是最常用于浏览器的 MQTT 客户端库,但它对初始化参数非常敏感,漏掉任意一个都可能静默失败。
立即学习“前端免费学习笔记(深入)”;
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
-
host:必须是域名或 IP,不能带ws://前缀(它自己拼),但port必须匹配 Broker 的 WebSocket 端口(如8083) -
useSSL:布尔值,不是字符串;wss时设为true,否则即使 URL 是wss://也会降级成ws -
userName和password:如果 Broker 开了鉴权,这两个字段不能为空字符串,也不能传null;传空字符串等效于无认证,传null会导致连接拒绝
示例片段:
const client = new Paho.MQTT.Client('broker.example.com', 8083, 'webclient-' + Math.random().toString(16).substr(2, 8));
client.connect({
userName: 'device001',
password: 's3cr3t',
useSSL: true,
onSuccess: () => console.log('connected'),
onFailure: (e) => console.error('connect failed:', e.errorMessage)
});
订阅主题后收不到消息?检查 QoS 和保留消息设置
仪表盘刚连上就期望立刻看到设备最新温度值,但经常空白——这通常不是代码问题,而是 MQTT 语义和 Broker 配置没对齐。
- 如果设备发的是
QoS 0消息,且你订阅发生在设备发布之后,那这条消息就彻底丢失了(“最多一次”) - 想一连上就拿到最新值,设备端必须发带
retain = true的消息;同时 Broker 要允许保留消息(Mosquitto 默认开启,EMQX 需确认retainer插件启用) - 前端订阅时不要加
qos: 1参数:浏览器客户端不支持 QoS 1 的重传机制,强行设会导致连接异常断开
验证方法:用命令行工具先确认数据存在:mosquitto_sub -h broker.example.com -p 8083 -t 'sensor/room1/temp' -R -v -u device001 -P s3cr3t(-R 表示只取保留消息)
页面刷新后连接中断,如何维持状态
浏览器页面刷新等于销毁整个 JS 上下文,WebSocket 连接必然断开。MQTT 协议本身不提供跨页面会话恢复能力,靠的是 Broker 的「持久会话(cleanSession = false)」+ 客户端重连逻辑。
-
cleanSession: false必须在首次连接时就设好,之后每次重连用相同clientId,Broker 才会投递离线期间的 QoS 1 消息 - 但浏览器无法真正“离线缓存”未送达消息,所以更现实的做法是:页面加载后立即重连,并在
onMessageArrived中做防重处理(比如比对时间戳,丢弃旧数据) - 不要依赖
onConnectionLost做优雅降级——它触发时机不可控,建议用定时ping主题(如每 30 秒发heartbeat/client-id)来主动探测连接健康度
真正容易被忽略的一点:MQTT over WebSocket 的心跳由客户端和服务端共同维护,但浏览器标签页进入后台时,JS 定时器可能被节流甚至暂停,导致心跳超时断连。解决方案是监听 visibilitychange 事件,在切回前台时强制重连。


















