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

React+Next应用连接HiveMQ MQTT失败,寻求ESP32 JS通信方案

问题描述

我基于React+Next开发应用,需要连接并控制ESP32,选择了HiveMQ的MQTT方案,但浏览器控制台持续循环报错:

WebSocket connection to 'ws://79642a966da549118f1128bb058d42ce.s2.eu.hivemq.cloud:8883/' failed:

已严格遵循HiveMQ官方文档操作,但问题仍未解决。希望有人帮忙排查该问题,或推荐更合适的JS与ESP32通信方案。我的index.tsx代码如下:

export default function Home() {
    const options = {
        username: 'gio.nacimento',
        password: 'Gio133ebu',
    };

    const mqtt = require('mqtt');

// connect to your cluster, insert your host name and port
    const client = mqtt.connect('tls://79642a966da549118f1128bb058d42ce.s2.eu.hivemq.cloud:8883', options);

// prints a received message
    client.on('message', function(topic: any, message: any) {
        console.log(String.fromCharCode.apply(null, message)); // need to convert the byte array to string
    });

// reassurance that the connection worked
    client.on('connect', () => {
        console.log('Connected!');
    });

// prints an error message
    client.on('error', (error: any) => {
        console.log('Error:', error);
    });

// subscribe and publish to the same topic
    client.subscribe('messages');
    client.publish('messages', 'Hello, this message was received from the app!');

    const test = (): void =>{
        client.subscribe('messages');
        client.publish('messages', 'Hello, this message was received from the app by clicking!');
    }

    return (
        <div className='flex justify-center items-center flex-col'>
            <h1>Controle de LED</h1>
            <button onClick={test}>Test server</button>
        </div>
    )
}

一、MQTT连接失败排查方案

1. 协议与端口不匹配

你使用的是tls://协议,但报错显示浏览器尝试连接ws://端口8883。HiveMQ Cloud的WebSocket over TLS专属端口是8884,8883是原生MQTT的TLS端口,浏览器环境仅支持WebSocket协议,因此连接地址需修改为:

wss://79642a966da549118f1128bb058d42ce.s2.eu.hivemq.cloud:8884

2. Next.js组件内客户端初始化逻辑错误

直接在组件顶层初始化MQTT客户端会导致组件每次渲染都重建连接,引发循环重连,这也是控制台循环报错的核心原因之一。需用useEffect钩子包裹初始化逻辑,确保仅执行一次:

import { useEffect, useRef } from 'react';
import mqtt from 'mqtt'; // 改用ES模块导入,避免require导致的类型问题

export default function Home() {
    const options = {
        username: 'gio.nacimento',
        password: 'Gio133ebu',
    };
    const clientRef = useRef<mqtt.Client | null>(null);

    useEffect(() => {
        const client = mqtt.connect('wss://79642a966da549118f1128bb058d42ce.s2.eu.hivemq.cloud:8884', options);
        clientRef.current = client;

        client.on('message', (topic, message) => {
            console.log(message.toString()); // 直接用toString转换字节数组更简洁
        });

        client.on('connect', () => {
            console.log('Connected!');
            client.subscribe('messages');
            client.publish('messages', 'Hello, this message was received from the app!');
        });

        client.on('error', (error) => {
            console.log('Error:', error);
        });

        // 组件卸载时断开连接,避免内存泄漏
        return () => {
            client.end();
        };
    }, []); // 空依赖数组确保初始化仅执行一次

    const test = () => {
        clientRef.current?.publish('messages', 'Hello, this message was received from the app by clicking!');
        // 无需重复订阅,连接成功时已完成订阅
    }

    return (
        <div className='flex justify-center items-center flex-col'>
            <h1>Controle de LED</h1>
            <button onClick={test}>Test server</button>
        </div>
    )
}

3. 认证与权限检查

  • 确认HiveMQ Cloud控制台已添加该用户名和密码,且权限设置允许发布/订阅messages主题;
  • 若开启了IP白名单,检查当前设备IP是否在允许列表内。

二、替代通信方案

如果MQTT方案仍存在问题,可考虑以下两种更直接的方案:

1. ESP32作为WebSocket服务器

在ESP32上通过ArduinoWebsockets库搭建WebSocket服务器,React应用直接通过ws://<ESP32局域网IP>:端口连接,无需中间MQTT broker。

  • 优势:延迟低、架构简单,适合局域网内设备控制;
  • 劣势:无法直接跨公网访问(需额外配置端口映射或内网穿透)。

2. HTTP API+ESP32 WebServer

在ESP32上搭建HTTP服务器,React应用通过fetch或axios发送GET/POST请求控制设备(例如http://<ESP32IP>/led?state=on)。

  • 优势:前端实现简单,无需额外MQTT客户端依赖;
  • 劣势:无法实时接收设备推送的消息(需结合轮询或WebSocket补充)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:12:04