Как подключить React к MQTT через WSS

Я пытаюсь подключиться к MQTT Broker, используя MQTT.js в своем приложении React, но получаю сообщение об ошибке протокола WSS.

Во-первых, мой файл 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

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.info("client: ", mqttClient);

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

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

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

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

Я могу подключиться к хосту mqtts://my.domain.io:3941 на своем локальном устройстве, но не могу подключиться к хосту wss://my.domain.io:3942 в производственной среде, поскольку мне нужно подключиться через HTTPS. Кроме того, я могу подключиться к wss://my.domain.io:3942 и без проблем выполнять операции публикации/подписки, используя Python, MQTT Box и MQTT Explorer.

СС из MQTT Box:

ОБНОВЛЯТЬ:

# 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()

Мои журналы Mosquitto выглядят следующим образом. Мое серверное приложение, работающее в локальной среде, может подключаться к порту 3941 без сертификата, тогда как мое приложение React может подключаться только к порту 39393 без сертификата.

Когда мое приложение React в производственной среде пытается подключиться к порту 39393, моя консоль показывает:

Когда он пытается подключиться к порту 3942, моя консоль показывает:

Наконец, хотя мое приложение React в производственной среде настроено на порт 39393 или 3942, в моих журналах Mosquitto данные не отображаются.

Итак, я хочу подключить React к MQTT через WSS на моем рабочем сервере.

«Я не могу подключиться» — это недостаточно подробностей, чтобы мы могли помочь. Расскажите, пожалуйста, что происходит при попытке подключения (появляется ли ошибка, что отображается на вкладке сети в консоли браузера/инструментах разработки, есть ли что-нибудь в журнале Mosquitto и т. д.). MRE также поможет, поскольку не совсем понятно, где ваш пример кода вписывается в более широкое приложение ( это руководство может помочь).

Brits 16.05.2024 22:59

@Британцы, вы правы, извините, я обновил свой пост.

nidea1 17.05.2024 08:36

Страница, обслуживаемая через HTTPS, не сможет подключиться к ws (только wss браузер не позволяет безопасной странице устанавливать небезопасные соединения). Соединение wss не установлено, но вы не указали причину этого на снимке экрана журнала (и это относится к подписке, которая не показана в вашем коде). Пожалуйста, сосредоточьте свой вопрос на том или ином сервере (локальный или производственный); в противном случае все запутается (ваш журнал Mosquitto не совпадает со снимком экрана браузера wss).

Brits 17.05.2024 22:30

@Brits Когда я попытался подключиться к WSS через https, я не смог подключиться, и Mosquitto не смог его зарегистрировать.

nidea1 18.05.2024 13:29

На вашем снимке экрана мы видим, что соединение не установлено, но не можем увидеть причину, потому что вы не расширили эти строки.

Brits 18.05.2024 20:10

@Brits Не было ничего описательного, всего несколько названий пакетов.

nidea1 19.05.2024 08:08

Пожалуйста, рассмешите меня (трассировка стека часто помогает отследить проблему); информация из вкладки сети также может быть полезна (чтобы посмотреть, какой ответ на запрос wss). Что касается логов Mosquitto, меня интересует только попытка подключения через wss (из браузера, через который была открыта страница https, ничего работать не будет). Обратите внимание, что cafile в конфигурации mosquitto необходим только при использовании клиентских сертификатов (и их невозможно использовать в браузере).

Brits 19.05.2024 11:35

@Brits, я не знаю, в консоли браузера я вижу только имена пакетов, а на стороне Mosquitto не было журналов на стороне браузера для wss, так что мой мозг действительно поджарен.

nidea1 19.05.2024 17:42

ОК, поскольку вы приняли ответ, этот вопрос будет считаться решенным...

Brits 19.05.2024 22:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
9
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У меня возникла проблема, из-за которой я не мог подключиться к защищенному брокеру MQTT по адресу wss://dash.meetlarry.io:3942 через HTTPS, находясь на сервере React Linux. Шаги, которые я выполнил для решения этой проблемы, следующие:

  1. Сначала я изменил файлы конфигурации Nginx, включив в них MQTT. конфигурация, поскольку на сервере React уже были конфигурации для сертификаты:

    # React App Server
    server {
        server_name my.domain.io;
    
        root /var/www/html/app/build;
        index index.html;
    
        listen 443 ssl;
        ssl_certificate /etc/letsencrypt/live/my.domain.io/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/my.domain.io/privkey.pem;
    
        location / {
            try_files $uri /index.html;
        }
    
        location /mqtt {
            proxy_pass http://localhost:39393;  # Mosquitto WebSocket port
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
        }
    }
    
    # Redirect HTTP to HTTPS for React App
    server {
        listen 80;
        server_name my.domain.io;
        return 301 https://$host$request_uri;
    }
    
  2. Затем я обновил код в React следующим образом:

    const options = {
        host: "my.domain.io", // current server name with certificate
        port: 443, // port listened by nginx
        path: '/mqtt', // location assigned in nginx
        protocol: 'wss', // protocol
        keepalive: 60,
        clientId: `${user.username}_${user.id}_${user.tenant}_${Date.now()}`,
        username: "username",
        password: "password",
        rejectUnauthorized: false
    };
    const mqttClient = mqtt.connect(options);
    setClient(mqttClient);
    
  3. Далее я обновил конфигурации MQTT на стороне DRF:

    class MQTTClient:
        def __init__(self, broker, port, username, password):
            self.broker = broker
            self.port = port
            self.username = username
            self.password = password
    
            client_id = f"larry_hotline-{random.randint(0, 1000)}"
            self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id, transport = "websockets")
    
        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()
    
  4. Я запустил свое приложение Django на порту WebSocket 3942, чтобы гарантировать передачу сообщений, и это решило странную проблему.

Причина, по которой я прибег к этому решению, заключается в том, что я пытался сертифицировать IP-адрес моего MQTT-брокера и подключиться, введя этот IP-адрес вместо имени домена через MQTT.js, но обе попытки не увенчались успехом. Я бы предпочел создать специальный сертификат для брокера MQTT и напрямую подключиться к MQTT.js. Если кому-то уже удавалось подключиться таким способом, я был бы очень рад, если бы мне объяснили и этот метод :)

Другие вопросы по теме