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

React应用通过WSS连接MQTT Broker的问题求助

生产环境React应用通过WSS连接MQTT Broker失败排查与解决

问题概述

我在React应用中使用MQTT.js连接MQTT Broker时遇到WSS协议相关错误:

  • 本地设备可正常连接mqtts://my.domain.io:3941
  • Python、MQTT Box、MQTT Explorer均可连接wss://my.domain.io:3942并完成发布/订阅操作
  • 生产环境React应用无法连接wss://my.domain.io:3942;尝试连接39393端口时被浏览器阻止,且两种连接请求均未出现在Mosquitto日志中

配置与代码信息

Mosquitto配置文件(mosquitto.conf)

# mosquitto.conf

pid_file /run/mosquitto/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

allow_anonymous false
password_file /etc/mosquitto/passwd

listener 3940
protocol mqtt

listener 39393
protocol websockets

listener 3941
protocol mqtt
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key

listener 3942
protocol websockets
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key

React应用连接代码(some.jsx)

// some.jsx

useEffect(() => {
    let reconnectAttempts = 0;
    try {
        if (user && !client) {
            const host = "ws://my.domain.io:39393"
            // const host = "wss://my.domain.io:3942"
            const options = {
                keepalive: 60,
                clientId: `${user.username}_${user.id}_${user.tenant}_${Date.now()}`,
                username: "username",
                password: "password",
                clean: true,
                rejectUnauthorized: false
            };
            const mqttClient = mqtt.connect(host, options);
            setClient(mqttClient);
            console.log("client: ", mqttClient);

            mqttClient.on("connect", () => {
                console.log("Connected to MQTT broker");
                setIsConnected(true);
                setIsReconnecting(false);
                setIsDisconnected(false);
                reconnectAttempts = 0;
            });
            
            mqttClient.on("disconnect", () => {
                console.log("Disconnected to MQTT broker");
                setIsConnected(false);
                setIsDisconnected(true);
            });
            
            mqttClient.on("close", (err) => {
                console.log("Closed connection to MQTT broker", err);
            });

            mqttClient.on("reconnect", () => {
                reconnectAttempts++;
                setIsReconnecting(true);

                if (reconnectAttempts > 5) {
                    mqttClient.end();
                    console.log("Reconnect attempts exceeded. Closing connection to MQTT broker");
                    setIsConnected(false);
                    setIsDisconnected(true);
                    return;
                }
                console.log("Reconnecting to MQTT broker", reconnectAttempts);
            });
            
            mqttClient.on("error", (err) => {
                console.log("Error from MQTT broker", err); 
            });
        }   
    } catch (error) {
        console.error("Error connecting to MQTT broker", error);
    }

    return () => {
        if (client) {
            console.log("MQTT Hook cleanup")
            client.end();
            setClient(null);
        }
    }
}, [user, client]);

Python测试连接代码(更新内容)

# some.py
def connect(self):
    self.client.on_message = self.on_message
    self.client.on_connect = self.on_connect
    self.client.on_disconnect = self.on_disconnect
    
    self.client.tls_set(cert_reqs=ssl.CERT_NONE)
    
    self.client.username_pw_set(self.username, self.password)
    
    self.client.connect(self.broker, self.port, keepalive=10)
    self.client.loop_start()

报错信息

  1. 连接39393端口时:浏览器控制台报错Mixed Content: The page at 'https://xxx' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://my.domain.io:39393'. This request has been blocked; this endpoint must be available over WSS.
  2. 连接3942端口时:浏览器控制台报错WebSocket connection to 'wss://my.domain.io:3942/' failed

排查与解决方案

1. 解决混合内容问题(39393端口)

生产环境页面通过HTTPS加载,浏览器会强制阻止非安全的WS连接,必须使用WSS协议。因此39393端口仅适合本地测试,生产环境需切换到3942端口的WSS连接。

2. 修复WSS连接失败(3942端口)

端口与防火墙验证

  • 确认服务器3942端口已对外开放,防火墙/安全组规则允许外部访问
  • 在服务器本地执行wscat -c wss://localhost:3942,验证Broker的WSS服务是否正常

证书配置检查

  • 确保broker.crt包含完整证书链(若使用第三方CA签发,需附加中间证书)
  • 验证证书域名与my.domain.io完全匹配,无IP或泛域名不匹配问题
  • 通过openssl x509 -in /etc/mosquitto/certs/broker.crt -text -noout检查证书是否过期

MQTT.js参数调整

  • 修正WSS URL拼写:确保使用完整格式wss://my.domain.io:3942(原代码注释中的URL缺少闭合引号)
  • 若使用自签名/私有CA证书,需在连接参数中指定CA证书:
    import caCert from './ca.crt'; // 导入CA证书文件
    const options = {
        // ...其他参数
        ca: caCert,
        rejectUnauthorized: false // 仅临时测试使用,生产环境建议设为true并确保证书可信
    };
    

生产环境反向代理配置(推荐)

通过Nginx反向代理转发WSS请求,避免直接暴露MQTT端口:

server {
    listen 443 ssl;
    server_name my.domain.io;

    ssl_certificate /path/to/your/cert.crt;
    ssl_certificate_key /path/to/your/key.key;

    location /mqtt {
        proxy_pass http://localhost:3942;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

此时React应用连接URL改为wss://my.domain.io/mqtt,无需指定端口。

3. 日志调试

  • 开启Mosquitto debug日志:在mosquitto.conf中添加log_type debug,重启服务后查看/var/log/mosquitto/mosquitto.log,确认是否有连接请求记录
  • 增强React错误日志输出:
    mqttClient.on("error", (err) => {
        console.error("MQTT Error Details:", err.message, err.stack); 
    });
    

内容的提问来源于stack exchange,提问作者nidea1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:14:56