Pruebas de brokers

Cómo probar MQTT sobre WebSockets (ws y wss)

Prueba un endpoint MQTT WebSocket paso a paso: la ruta /mqtt, el subprotocolo mqtt, handshake con curl y wscat, DevTools y un test con MQTT.js.

Actualizado · 8 min de lectura

Cómo probar MQTT sobre WebSockets (ws y wss)

Para probar MQTT sobre WebSockets, verifica la conexión en dos etapas: primero el upgrade HTTP (URL correcta, ruta correcta, subprotocolo mqtt, 101 Switching Protocols) y después una sesión MQTT real dentro del socket (CONNECT, CONNACK, publish, subscribe). La mayoría de los problemas con WebSockets —404, sockets cerrados, bloqueos por contenido mixto— ocurren en la primera etapa, antes de que MQTT entre siquiera en juego.

Los ejemplos usan broker.connectmq.com: ws:// en el puerto 8083 y wss:// en el puerto 8084, ambos con la ruta /mqtt.

Cómo es una conexión MQTT WebSocket que funciona

Una URL MQTT WebSocket tiene cuatro partes, y cualquiera de ellas puede estar mal:

ParteEjemploError típico
Esquemawss://ws:// desde una página HTTPS (bloqueado como contenido mixto)
Hostbroker.connectmq.comDirección IP con wss: el certificado no coincide
Puerto8084Usar el puerto TCP 1883 o el puerto TLS 8883
Ruta/mqttRuta ausente o incorrecta: 404 Not Found

El cliente envía además la cabecera Sec-WebSocket-Protocol: mqtt. El broker debe responder con HTTP/1.1 101 Switching Protocols y devolver Sec-WebSocket-Protocol: mqtt. A partir de ahí, el socket transporta paquetes MQTT binarios normales: el mismo CONNECT y CONNACK que sobre TCP. Para el contexto, consulta MQTT sobre WebSockets.

Etapa 1: prueba el handshake

Con curl

curl puede enviar la petición de upgrade a mano y mostrarte la respuesta en bruto. Así aíslas la parte HTTP de cualquier librería MQTT:

Comprobación del handshake WebSocket
curl -i --http1.1 --max-time 5 \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  -H "Sec-WebSocket-Protocol: mqtt" \
  https://broker.connectmq.com:8084/mqtt

Usa http://...:8083/mqtt para probar el listener sin cifrar. Un endpoint sano responde:

Respuesta esperada
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: mqtt

Después curl espera hasta --max-time porque el socket sigue abierto: es lo esperado. Otras respuestas te indican qué corregir:

RespuestaSignificado
101 sin Sec-WebSocket-Protocol: mqttEl broker o el proxy descarta el subprotocolo; los navegadores cerrarán el socket
404 Not FoundRuta incorrecta: prueba /mqtt, / o la ruta documentada de tu broker (detalles)
400 Bad Request / 426 Upgrade RequiredFaltan las cabeceras de upgrade, a menudo por un proxy que no las reenvía
502 Bad GatewayEl proxy inverso no llega al listener WebSocket del broker
Empty reply from server o resetEl puerto es MQTT/TLS normal, no WebSocket
Error de certificado SSLLos mismos problemas TLS que en 8883: el certificado debe coincidir con el hostname

Si el broker está detrás de Nginx u otro proxy, un 400 o un subprotocolo ausente casi siempre significan que las cabeceras Upgrade y Connection no se reenvían; consulta MQTT detrás de un proxy Nginx.

Con wscat

wscat es un pequeño cliente WebSocket que negocia el subprotocolo correctamente:

wscat
npx wscat -c wss://broker.connectmq.com:8084/mqtt -s mqtt

Connected (press CTRL+C to quit) significa que el handshake y el subprotocolo están bien. Unos segundos después el broker cierra el socket porque no llegó ningún paquete MQTT CONNECT: es normal y, de hecho, confirma que hay un broker MQTT escuchando. Sin -s mqtt, muchos brokers rechazan el upgrade, lo que sirve como prueba negativa.

Etapa 2: prueba una sesión MQTT real

Los clientes de línea de comandos de mosquitto no pueden conectarse por WebSockets, así que usa un cliente compatible. Lo más rápido es el cliente MQTT online: introduce la URL wss://, conéctate, suscríbete a un topic de prueba y publica en él. Si funciona, el lado del broker es correcto y cualquier problema restante está en tu aplicación.

Para una comprobación automática, este script con MQTT.js 5 funciona en Node.js o, casi sin cambios, en el navegador:

ws-check.mjs (MQTT.js 5)
import mqtt from "mqtt";

const url = "wss://broker.connectmq.com:8084/mqtt";
const topic = `testmqtt/ws/${Math.random().toString(16).slice(2, 10)}`;

const client = mqtt.connect(url, {
  protocolVersion: 5,
  username: process.env.MQTT_USER,
  password: process.env.MQTT_PASS,
  connectTimeout: 5000,
  reconnectPeriod: 0, // fallar rápido durante la prueba
});

const started = Date.now();
client.on("connect", (connack) => {
  console.log(`CONNACK reason ${connack.reasonCode ?? 0} after ${Date.now() - started} ms`);
  client.subscribe(topic, { qos: 1 }, () => client.publish(topic, "ping over websocket", { qos: 1 }));
});
client.on("message", (t, payload) => {
  console.log(`round trip ok on ${t}: ${payload}`);
  client.end();
});
client.on("error", (err) => { console.error("error:", err.message); process.exit(1); });
client.on("close", () => console.log("socket closed"));

MQTT.js establece el subprotocolo mqtt automáticamente. Python también sirve: paho-mqtt 2.x con transport="websockets":

ws_check.py (paho-mqtt 2.x)
import os
import paho.mqtt.client as mqtt

c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, transport="websockets", protocol=mqtt.MQTTv5)
c.ws_set_options(path="/mqtt")
c.tls_set()  # quítalo para ws:// en el puerto 8083
c.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
c.on_connect = lambda cl, u, f, rc, p: print("CONNACK:", rc)
c.connect("broker.connectmq.com", 8084)
c.loop_forever()

La ruta WebSocket por defecto de paho ya es /mqtt, así que ws_set_options es opcional aquí, pero los brokers que usan / o una ruta propia responden con 404 hasta que la indicas explícitamente.

Depurar con las DevTools del navegador

Cuando una aplicación web no consigue conectarse, el navegador te muestra todos los detalles del handshake:

  1. Abre DevTools → Network, filtra por WS (Chrome) o elige WS en el filtro de tipo (Firefox) y recarga la página.
  2. Haz clic en la petición del socket. En Headers, comprueba el estado (101), la URL y la ruta, y que tanto la petición como la respuesta incluyan Sec-WebSocket-Protocol: mqtt.
  3. Abre la pestaña Messages (Chrome) o Response (Firefox). La primera trama saliente es el CONNECT MQTT binario; la primera entrante es el CONNACK. Si el CONNECT sale y el socket se cierra sin CONNACK, el broker rechazó la sesión MQTT (credenciales, client ID), no el WebSocket.
  4. Revisa la Console en busca de errores como estos:
Errores típicos en la consola
WebSocket connection to 'wss://broker.example.com:8084/mqtt' failed:
Mixed Content: The page at 'https://app.example.com/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://broker.example.com:8083/mqtt'. This request has been blocked; this endpoint must be available over WSS.

El primero, sin nada después de los dos puntos, es el fallo genérico del navegador: normalmente puerto, ruta o certificado incorrectos; revisa la pestaña Network. El segundo solo se resuelve cambiando a wss:// (contenido mixto). Un código de cierre 1006 significa que la conexión se cortó sin una trama de cierre correcta, a menudo por un timeout del proxy o porque el broker rechazó la conexión. Para la lista completa de causas, consulta MQTT WebSocket connection failed.

Checklist de pruebas WebSocket

  1. curl contra la URL wss:// devuelve 101 y repite Sec-WebSocket-Protocol: mqtt.
  2. wscat con -s mqtt conecta; sin él, el broker rechaza o cierra.
  3. Un cliente real recibe un CONNACK y completa un ciclo publish/subscribe.
  4. El navegador conecta desde una página HTTPS con wss://, sin errores en la consola.
  5. A través de tu proxy o balanceador, las conexiones inactivas sobreviven más que el intervalo de keep-alive.
  6. Las credenciales y las ACLs se comportan igual en el listener WebSocket que en TCP.

Prueba el endpoint WebSocket en tu navegador

Los problemas de WebSocket solo parecen misteriosos hasta que los divides en dos. Demuestra el upgrade HTTP con curl o wscat, después la sesión MQTT con un cliente real, y en minutos sabrás si tienes que corregir la URL, el proxy o las credenciales MQTT.

Preguntas frecuentes

¿Cuál es la ruta WebSocket de MQTT?

No hay un estándar único. /mqtt es la más común (la usan EMQX, HiveMQ y ConnectMQ, y los proxies delante de Mosquitto suelen enrutarla), pero algunos brokers escuchan en / o en una ruta propia. Una ruta incorrecta suele devolver HTTP 404 durante el handshake.

¿Qué subprotocolo WebSocket usa MQTT?

mqtt, tanto para MQTT 3.1.1 como para MQTT 5. Los clientes antiguos de MQTT 3.1 usaban mqttv3.1. El cliente lo envía en Sec-WebSocket-Protocol y el broker debe devolverlo en la respuesta 101; si no lo hace, los navegadores cierran la conexión.

¿Puede mosquitto_pub conectarse por WebSockets?

No. Los clientes de línea de comandos de mosquitto solo hablan MQTT sobre TCP y TLS. Para probar un listener WebSocket usa un cliente en el navegador, MQTT.js, paho-mqtt con transport="websockets" o un cliente de escritorio como MQTTX.