ReactJS应用无法连接Docker部署的Mosquitto MQTT WebSocket
问题:ReactJS通过WebSocket连接Docker中的Mosquitto失败,日志反复显示连接关闭
我在Docker容器中运行2.0.15版本的Eclipse Mosquitto MQTT Broker,设备通过MQTT协议能正常连接,但ReactJS应用使用WebSocket连接时失败,容器日志反复出现Client react-client closed its connection。
相关配置与代码
mosquitto.conf配置
per_listener_settings true persistence true persistence_location /mosquitto/data/ #log_dest file /mosquitto/log/mosquitto.log ## Authentication ## allow_anonymous false listener 8885 password_file /mosquitto/config/password.txt # websockets connections from react listener 9001 protocol websockets socket_domain ipv4
ReactJS应用代码
import React, { useState, Fragment } from 'react'; import mqtt from "precompiled-mqtt"; var options = { protocol: 'ws', username: 'smart_home_mqtt_user', password: 'testtest', clientId: 'react-client', }; var client = mqtt.connect('ws://192.168.0.160:9001',options); client.on('connect', () => { console.log("CONNECTED to broker"); }); // MQTT topic client.subscribe('test'); function MqttDash() { var note; client.on('message', function (topic, message) { note = message.toString(); // Updates React state with message setMsg(note); console.log(note); client.end(); }); // Sets default React state const [msg, setMsg] = useState(<Fragment><em>...</em></Fragment>); return ( <div > <h1>Hello MQTT in React</h1> <p>The message payload is: {msg}</p> </div> ); } export default MqttDash;
Mosquitto容器日志输出
1664520991: mosquitto version 2.0.15 starting 1664520991: Config loaded from /mosquitto/config/mosquitto.conf. 1664520991: Opening ipv4 listen socket on port 8885. 1664520991: Opening ipv6 listen socket on port 8885. 1664520991: Opening websockets listen socket on port 9001. 1664520991: mosquitto version 2.0.15 running 1664521055: Client react-client closed its connection. 1664521056: Client react-client closed its connection. 1664521057: Client react-client closed its connection. 1664521058: Client react-client closed its connection. 1664521059: Client react-client closed its connection. 1664521060: Client react-client closed its connection.
解决方案
1. 修复Mosquitto WebSocket监听器的认证配置
由于开启了per_listener_settings true,全局的allow_anonymous false不会自动应用到WebSocket监听器,需要单独配置认证规则:
修改mosquitto.conf中WebSocket监听部分,添加密码文件配置:
listener 9001 protocol websockets socket_domain ipv4 password_file /mosquitto/config/password.txt # 与MQTT端口共用同一个密码文件
2. 修正React代码中的逻辑问题
- 避免在组件外部初始化MQTT客户端,防止组件重复渲染时创建多个客户端实例
- 移除
client.end()调用,避免收到一条消息就断开连接 - 使用
useEffect管理客户端生命周期,确保组件卸载时正确断开连接 - 生成随机ClientID,避免重复连接冲突
修改后的React代码:
import React, { useState, useEffect, Fragment } from 'react'; import mqtt from "precompiled-mqtt"; function MqttDash() { const [msg, setMsg] = useState(<Fragment><em>...</em></Fragment>); let client = null; useEffect(() => { const options = { username: 'smart_home_mqtt_user', password: 'testtest', clientId: `react-client-${Math.random().toString(16).substr(2, 8)}`, // 随机生成ClientID }; client = mqtt.connect('ws://192.168.0.160:9001', options); client.on('connect', () => { console.log("CONNECTED to broker"); client.subscribe('test'); // 连接成功后再订阅主题 }); client.on('message', (topic, message) => { const note = message.toString(); setMsg(note); console.log(note); }); client.on('error', (err) => { console.error('MQTT连接错误:', err); }); client.on('close', () => { console.log('MQTT连接关闭'); }); // 组件卸载时断开连接 return () => { if (client) { client.end(); } }; }, []); return ( <div> <h1>Hello MQTT in React</h1> <p>The message payload is: {msg}</p> </div> ); } export default MqttDash;
3. 验证Docker端口映射
确保启动容器时已经映射9001端口到主机:
docker run -d -p 8885:8885 -p 9001:9001 -v ./mosquitto/config:/mosquitto/config -v ./mosquitto/data:/mosquitto/data eclipse-mosquitto:2.0.15
4. 开启详细日志排查
修改mosquitto.conf开启全量日志,查看具体失败原因:
log_dest file /mosquitto/log/mosquitto.log log_type all
内容的提问来源于stack exchange,提问作者pastor_j
相关产品推荐
相关产品推荐

