Guides

MQTT sur WebSockets : se connecter depuis le navigateur

MQTT sur WebSockets expliqué : pourquoi les navigateurs en ont besoin, ws ou wss, le chemin /mqtt, les ports courants, le contenu mixte et un exemple avec MQTT.js.

Mis à jour · 7 min de lecture

MQTT fonctionne normalement sur une connexion TCP brute, sur le port 1883 (ou 8883 avec TLS). Les navigateurs ne peuvent pas ouvrir de sockets TCP bruts : une application web ne peut donc pas parler MQTT de cette façon. La solution, c’est MQTT sur WebSockets : les mêmes paquets MQTT, transportés dans une connexion WebSocket que tous les navigateurs prennent en charge. Ce guide explique son fonctionnement et comment éviter les erreurs qui piègent la plupart des développeurs.

Pourquoi les navigateurs ont besoin des WebSockets

Pour des raisons de sécurité, le JavaScript d’une page web ne peut établir de connexions réseau qu’à travers les API du navigateur — fetch, XMLHttpRequest, WebSocket, WebRTC et WebTransport. Aucune ne peut ouvrir une connexion TCP arbitraire vers le port 1883. Les WebSockets conviennent naturellement à MQTT, car ils offrent un canal binaire, bidirectionnel et de longue durée — exactement ce dont MQTT a besoin.

Les WebSockets ne servent pas qu’aux navigateurs. Ils sont aussi utiles lorsque :

  • un pare-feu ou un proxy d’entreprise n’autorise que le trafic web sur les ports 80 et 443 ;
  • vous voulez que MQTT partage un load balancer ou un reverse proxy avec vos services HTTP ;
  • vous construisez un tableau de bord, un outil d’administration ou une application web mobile affichant des données d’appareils en direct.

Comment fonctionne MQTT sur WebSockets

  1. Le client ouvre une connexion HTTP(S) et envoie une requête d’upgrade WebSocket vers une URL comme wss://broker.emqx.io:8084/mqtt, en demandant le sous-protocole mqtt.
  2. Le broker répond 101 Switching Protocols et la connexion devient un WebSocket.
  3. À partir de là, les paquets MQTT (CONNECT, PUBLISH, …) circulent dans des trames WebSocket binaires. Tout ce qui se trouve au-dessus du transport — QoS, messages retenus (retained), Last Will, propriétés MQTT 5 — fonctionne exactement comme sur TCP.

Le broker doit avoir un listener WebSocket activé. Ce listener tourne généralement sur un autre port que le listener TCP, et certains brokers attendent un chemin (path) précis.

Conséquence pratique : les navigateurs ne permettent pas au JavaScript de définir des en-têtes personnalisés sur une requête WebSocket. L’authentification se fait donc normalement au sein de MQTT, avec les champs nom d’utilisateur et mot de passe du paquet CONNECT, plutôt qu’avec des en-têtes HTTP ou des cookies.

ws ou wss

ws://wss://
ChiffrementAucun — identifiants et payloads en clairTLS, comme HTTPS
Utilisable depuis une page HTTPSNon (bloqué comme contenu mixte)Oui
Proxys et pare-feuParfois perturbéPasse généralement sur le port 443
Usage typeDéveloppement local uniquementTout le reste

Comme wss:// utilise la pile TLS du navigateur, le certificat du broker doit être reconnu par le navigateur. Un certificat auto-signé échouera silencieusement depuis JavaScript — ouvrez une fois l’URL https://host:port dans un onglet pour voir la véritable erreur de certificat.

Le contenu mixte : l’erreur navigateur la plus courante

Si votre page est servie en https:// (comme presque tous les sites), le navigateur bloque toute tentative d’ouverture d’une connexion ws://. La console affiche une erreur de contenu mixte ou de sécurité, et le client MQTT ne se connecte tout simplement jamais. La solution est toujours la même : utilisez l’endpoint wss:// du broker. Notre client MQTT en ligne est servi en HTTPS pour cette raison et ne se connecte qu’en wss://.

Ports et chemins

Il n’existe pas de port WebSocket standard unique pour MQTT ; chaque broker choisit le sien. Voici les endpoints des brokers publics de notre annuaire de brokers :

Brokerws://wss://Chemin
broker.hivemq.com80008884/mqtt
broker.emqx.io80838084/mqtt
test.mosquitto.org80808081n’importe lequel
mqtt.eclipseprojects.io80443/mqtt

Un mauvais chemin provoque généralement un échec du handshake (HTTP 404 ou connexion fermée) avant même que MQTT ne démarre. Un mauvais port aboutit le plus souvent à un timeout. Pour une vue complète des ports TCP, TLS et WebSocket, voir les ports MQTT expliqués.

Exemple : MQTT dans le navigateur avec MQTT.js

MQTT.js est le client JavaScript le plus utilisé et fonctionne aussi bien dans Node.js que dans le navigateur. Dans le navigateur, il utilise automatiquement les WebSockets :

browser.js
import mqtt from 'mqtt';

const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt', {
  clientId: `web-${crypto.randomUUID().slice(0, 8)}`,
  // username: 'user', password: 'secret',  // for private brokers
  reconnectPeriod: 2000,
});

client.on('connect', () => {
  client.subscribe('testmqtt/ws-demo/#');
  client.publish('testmqtt/ws-demo/hello', 'hello from the browser');
});

client.on('message', (topic, payload) => {
  console.log(topic, payload.toString());
});

client.on('error', (err) => console.error('MQTT error:', err.message));

Activer les WebSockets sur votre propre broker

Si vous exploitez votre propre broker, le listener WebSocket tient généralement en quelques lignes de configuration. Dans Mosquitto, par exemple, vous ajoutez un second listener à côté du listener TCP :

mosquitto.conf
listener 1883
protocol mqtt

listener 8080
protocol websockets

Pour wss://, vous pouvez soit configurer directement les certificats sur ce listener, soit — plus couramment — terminer TLS sur un reverse proxy en 443 et transférer le trafic WebSocket en clair vers le broker. Le proxy doit avoir la prise en charge des WebSockets activée :

Bloc location nginx
location /mqtt {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 1h;
}

Assurez-vous que le read timeout du proxy est plus long que votre intervalle de keep-alive MQTT ; sinon, le proxy ferme les connexions inactives et les clients subissent des déconnexions inexpliquées.

Checklist de dépannage

  • Vous utilisez le port 1883 ou 8883 depuis un navigateur ? Ce sont des ports TCP — passez au listener WebSocket.
  • Page en HTTPS, URL commençant par ws:// ? Contenu mixte — utilisez wss://.
  • Le handshake échoue immédiatement ? Vérifiez le chemin (/mqtt ou aucun) et le sous-protocole.
  • Derrière un reverse proxy ? Nginx et les proxys similaires doivent transmettre les en-têtes Upgrade et Connection et autoriser les connexions de longue durée.
  • Connecté puis éjecté ? C’est un problème au niveau MQTT — voir les erreurs de connexion MQTT.

Tester une connexion wss:// maintenant

Questions fréquentes

Pourquoi mon navigateur ne peut-il pas se connecter à MQTT sur le port 1883 ?

Les navigateurs ne peuvent pas ouvrir de sockets TCP bruts, et le port 1883 parle MQTT en clair sur TCP. Un client navigateur doit se connecter au listener WebSocket du broker, avec une URL ws:// ou wss:// et le bon port et chemin.

Quelle est la différence entre ws et wss pour MQTT ?

ws:// est une connexion WebSocket non chiffrée ; wss:// est un WebSocket sur TLS. Les pages servies en HTTPS ne peuvent utiliser que wss://, et wss:// est le seul choix raisonnable au-delà des tests locaux.

Quel chemin utiliser pour MQTT sur WebSockets ?

Cela dépend du broker. Beaucoup de brokers, dont EMQX et HiveMQ, utilisent /mqtt. Mosquitto accepte les connexions quel que soit le chemin. Consultez la documentation du broker ; un mauvais chemin échoue généralement pendant le handshake WebSocket.