MQTT sur WebSocket permet à une page web de publier et de s'abonner à un broker MQTT directement depuis le navigateur, sans relais backend intermédiaire. Dans ce tutoriel, vous verrez pourquoi les navigateurs ont besoin du transport WebSocket, quelle est la différence entre ws et wss, et comment créer une page HTML complète ainsi qu'un client Node.js qui dialoguent avec broker.connectmq.com.
Vous découvrez les brokers ? Lisez d'abord Qu'est-ce qu'un broker MQTT ? pour les bases du publish/subscribe.
Pourquoi les navigateurs ont besoin de MQTT sur WebSocket
Le MQTT natif fonctionne sur une simple connexion TCP, généralement sur le port 1883 (ou 8883 avec TLS). Les applications de bureau, les serveurs et les microcontrôleurs peuvent ouvrir librement des sockets TCP. Pas les navigateurs : pour des raisons de sécurité, le JavaScript d'une page web n'a accès qu'à HTTP, WebSocket et quelques autres transports gérés par le navigateur.
WebSocket résout ce problème. La connexion commence comme une requête HTTP ordinaire avec un en-tête Upgrade: websocket, et dès que le serveur répond 101 Switching Protocols, elle devient un canal binaire full-duplex. Les paquets MQTT (CONNECT, PUBLISH, SUBSCRIBE, etc.) sont alors transportés tels quels dans des trames WebSocket. Le client demande le sous-protocole mqtt pendant la négociation pour que le broker sache à quoi s'attendre.
Browser (MQTT.js) broker.connectmq.com:8084
|-- TLS handshake ------------------------------>|
|-- GET /mqtt Upgrade: websocket |
| Sec-WebSocket-Protocol: mqtt ---------------->|
|<-- 101 Switching Protocols ---------------------|
|== WebSocket frame [ MQTT CONNECT ] ============>|
|<= WebSocket frame [ MQTT CONNACK ] =============|
|== WebSocket frame [ MQTT SUBSCRIBE ] ==========>|
|<= WebSocket frame [ MQTT PUBLISH ] =============|
Du point de vue du broker, un client WebSocket n'est qu'un client MQTT parmi d'autres. Il peut dialoguer avec des appareils connectés en TCP, partager des topics avec eux et utiliser les mêmes niveaux de QoS, retained messages et fonctionnalités MQTT 5.
Usages typiques de MQTT sur WebSocket :
- Tableaux de bord IoT en temps réel qui se mettent à jour dès qu'un capteur publie
- Panneaux de contrôle dans le navigateur qui envoient des commandes aux appareils
- Outils de supervision et jumeaux numériques qui visualisent l'état des machines en temps réel
- Applications mobiles hybrides basées sur les technologies web
ws ou wss : ports et chemins sur ConnectMQ
Comme HTTP et HTTPS, WebSocket existe en version non chiffrée (ws://) et en version chiffrée par TLS (wss://).
| Transport | Schéma | Port | URL complète | Quand l'utiliser |
|---|---|---|---|---|
| MQTT (TCP) | mqtt:// | 1883 | mqtt://broker.connectmq.com:1883 | Appareils, serveurs, CLI |
| MQTT sur TLS | mqtts:// | 8883 | mqtts://broker.connectmq.com:8883 | Appareils et serveurs en production |
| WebSocket | ws:// | 8083 | ws://broker.connectmq.com:8083/mqtt | Tests locaux depuis une page http:// |
| WebSocket sécurisé | wss:// | 8084 | wss://broker.connectmq.com:8084/mqtt | Navigateurs et applications web en production |
Deux détails comptent :
- Le chemin est
/mqtt. Une URL WebSocket est une URL HTTP : elle comporte donc un chemin. Se connecter àwss://broker.connectmq.com:8084sans/mqttfait échouer la négociation. - Préférez wss. Les pages servies en HTTPS ne peuvent ouvrir que des connexions
wss://, et les identifiants envoyés enws://circulent en clair. ConnectMQ sert le WSS sur le port 8084 avec un certificat Let's Encrypt, que les navigateurs reconnaissent sans configuration supplémentaire.
Créer une page MQTT sur WebSocket avec MQTT.js
La page suivante est complète et autonome. Enregistrez-la sous index.html et ouvrez-la dans un navigateur. Elle charge MQTT.js depuis un CDN, se connecte anonymement au serveur MQTT public gratuit broker.connectmq.com (réservé aux tests, sans données de production), s'abonne à un topic unique et vous permet de publier des messages.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MQTT over WebSocket demo</title>
<script src="https://unpkg.com/mqtt@5.10.3/dist/mqtt.min.js"></script>
</head>
<body>
<p>Status: <span id="status">connecting...</span></p>
<input id="msg" value="Hello from the browser">
<button id="send">Publish</button>
<pre id="log"></pre>
<script>
const id = Math.random().toString(16).slice(2, 10);
const clientId = "web-" + id;
const topic = "connectmq/demo/" + id + "/chat";
const log = (line) => {
document.getElementById("log").textContent += line + "\n";
};
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId: clientId,
protocolVersion: 5,
clean: true,
keepalive: 30,
reconnectPeriod: 2000,
connectTimeout: 10000
});
client.on("connect", () => {
document.getElementById("status").textContent = "connected as " + clientId;
client.subscribe(topic, { qos: 1 }, (err, granted) => {
if (err) return log("Subscribe error: " + err.message);
log("Subscribed to " + granted[0].topic + " (QoS " + granted[0].qos + ")");
});
});
client.on("message", (t, payload) => {
log("[" + t + "] " + payload.toString());
});
client.on("reconnect", () => {
document.getElementById("status").textContent = "reconnecting...";
});
client.on("error", (err) => log("Error: " + err.message));
document.getElementById("send").onclick = () => {
const text = document.getElementById("msg").value;
client.publish(topic, text, { qos: 1 });
};
</script>
</body>
</html>
Lorsque vous cliquez sur Publish, le message part vers le broker via le WebSocket sécurisé et revient aussitôt par votre propre abonnement. Ouvrez la page dans deux onglets : chaque onglet obtient son propre topic aléatoire, ils ne se voient donc pas. Pour partager un topic, codez en dur le même topic connectmq/demo/<your-id>/chat dans les deux.
Quelques remarques sur les options :
clientIddoit être non vide et unique. La zone publique refuse un client ID vide, et deux clients portant le même ID n'arrêtent pas de s'éjecter mutuellement.protocolVersion: 5utilise MQTT 5. Indiquez4pour MQTT 3.1.1 si nécessaire.keepalive: 30fait envoyer au client un PINGREQ lorsque la connexion est inactive, afin que le broker et les éventuels proxys sachent qu'il est toujours vivant.reconnectPeriod: 2000fait se reconnecter automatiquement MQTT.js deux secondes après une coupure.
Vous pouvez aussi suivre les messages du navigateur depuis un terminal avec la CLI Mosquitto, puisque les clients TCP et WebSocket partagent les mêmes topics. Remplacez abc12345 par l'identifiant affiché dans le topic de la page :
mosquitto_sub -h broker.connectmq.com -p 1883 -i cli-watch-abc12345 -t "connectmq/demo/abc12345/#" -v
MQTT sur WebSocket avec Node.js
Node.js peut utiliser du TCP classique, mais WebSocket est utile lorsque votre serveur se trouve derrière un proxy ou un pare-feu qui n'autorise que du trafic de type HTTPS, ou lorsque vous souhaitez partager du code avec une application navigateur. Installez MQTT.js avec npm install mqtt et enregistrez ceci sous ws-client.mjs :
import mqtt from "mqtt";
const id = Math.random().toString(16).slice(2, 10);
const clientId = `node-${id}`;
const topic = `connectmq/demo/${id}/hello`;
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId,
protocolVersion: 5,
keepalive: 30,
});
client.on("connect", (connack) => {
console.log("Connected, CONNACK properties:", connack.properties);
client.subscribe(topic, { qos: 1 }, (err, granted) => {
if (err) throw err;
console.log("Granted:", granted);
client.publish(topic, JSON.stringify({ temp: 21.5, ts: Date.now() }), { qos: 1 });
});
});
client.on("message", (t, payload) => {
console.log(`Received on ${t}: ${payload.toString()}`);
client.end();
});
client.on("error", (err) => {
console.error("Connection error:", err.message);
client.end();
});
Lancez-le avec node ws-client.mjs. La sortie ressemble à ceci :
Connected, CONNACK properties: { receiveMaximum: 16, topicAliasMaximum: 65535 }
Granted: [ { topic: 'connectmq/demo/4df8521c/hello', qos: 1, nl: false, rap: false, rh: 0 } ]
Received on connectmq/demo/4df8521c/hello: {"temp":21.5,"ts":1790000000000}
La seule différence avec un client TCP, c'est l'URL. Remplacez-la par mqtt://broker.connectmq.com:1883 et le reste du code reste identique. Pour comprendre les valeurs qos ci-dessus, consultez Les niveaux de QoS MQTT expliqués.
Dépanner les connexions MQTT sur WebSocket
La plupart des problèmes se manifestent par une connexion qui n'atteint jamais l'événement connect ou qui se reconnecte sans cesse. Ouvrez les outils de développement du navigateur, regardez la Console et l'onglet Réseau (filtre WS), et comparez avec ce tableau.
| Symptôme | Cause probable | Solution |
|---|---|---|
| Erreur « Mixed Content », connexion bloquée | Une page https:// tente d'ouvrir une connexion ws:// | Utilisez wss://broker.connectmq.com:8084/mqtt |
| La négociation échoue, HTTP 404 dans l'onglet Réseau | Chemin absent ou incorrect | Ajoutez /mqtt à l'URL |
| La négociation échoue sur le 8083 ou le 8084 | Schéma et port inversés (ws sur 8084, wss sur 8083) | ws va avec 8083, wss avec 8084 |
| Vous soupçonnez un problème de CORS | WebSocket n'est pas soumis au CORS comme fetch/XHR | Cherchez la vraie cause : URL, port, TLS ou identifiants |
| Se connecte puis se déconnecte toutes les quelques secondes | Deux clients utilisent le même client ID | Générez un ID unique par onglet ou par appareil |
| Connexion refusée juste après le CONNECT | Client ID vide, ou nom d'utilisateur/mot de passe erroné | Définissez un client ID non vide ; vérifiez les identifiants du portail |
| Coupure après une période d'inactivité | Keepalive trop long pour un proxy ou un réseau mobile | Utilisez keepalive: 30 ou moins |
| Fonctionne en local, échoue sur un réseau d'entreprise | Un proxy ou un pare-feu bloque les ports non standard | Testez depuis un autre réseau, ou demandez à l'IT d'autoriser le trafic sortant vers le port 8084 |
Deux de ces cas méritent qu'on s'y attarde.
Contenu mixte
Les navigateurs bloquent les sous-ressources non sécurisées sur les pages sécurisées. Si votre tableau de bord est servi en https://, toute connexion ws:// est refusée avant même de quitter le navigateur, et le broker ne la voit jamais. La solution est toujours wss://. L'endpoint non chiffré ws://broker.connectmq.com:8083/mqtt n'est utile que pour des pages ouvertes depuis http://localhost ou un fichier local.
Conflits de client ID
MQTT n'autorise qu'une seule connexion par client ID. Lorsqu'une seconde connexion arrive avec le même ID, le broker ferme la première. Dans un navigateur, cela se produit souvent lorsqu'un utilisateur ouvre la même page dans deux onglets alors que le client ID est codé en dur. Avec la reconnexion automatique activée, les deux onglets se disputent alors l'ID indéfiniment. Ajoutez un suffixe aléatoire par onglet. Sur un broker ConnectMQ privé, les client IDs sont limités au client ID émis et à ses variantes _suffix : utilisez donc YOUR_CLIENT_ID_tab1, YOUR_CLIENT_ID_tab2, etc.
En production : utiliser les identifiants du portail
Le serveur MQTT public gratuit est destiné aux tests : tout ce qui y est publié est lisible par n'importe qui, et ses limites sont strictes (64 Ko par message, 10 messages par seconde et par client). Pour une vraie application, créez un broker privé dans le portail et connectez-vous avec les identifiants générés :
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId: "YOUR_CLIENT_ID_dashboard",
username: "YOUR_USERNAME",
password: "YOUR_PASSWORD",
protocolVersion: 5,
keepalive: 30,
});
Gardez ces points à l'esprit pour les applications navigateur :
- Utilisez toujours wss en production. Le nom d'utilisateur et le mot de passe sont envoyés dans le paquet CONNECT : le transport doit donc être chiffré.
- Considérez les identifiants côté navigateur comme visibles. Tout ce qui est envoyé à un navigateur peut être lu par son utilisateur. Donnez à l'application web ses propres identifiants plutôt que de réutiliser ceux des appareils, et évitez de les intégrer dans des pages publiques.
- Respectez les limites de votre offre. Chaque onglet ouvert est une connexion. L'offre Serverless (Free) autorise jusqu'à 25 connexions simultanées, ce qui convient aux prototypes. Les tableaux de bord de production sont mieux servis par Serverless (Paid), avec jusqu'à 1 000 connexions, ou par un cluster Dedicated.
- Gérez proprement les reconnexions. Affichez un indicateur d'état, et réabonnez-vous ou appuyez-vous sur une session persistante au retour de la connexion.
D'autres conseils de durcissement sont réunis dans Sécurité MQTT : les bonnes pratiques.
Démarrer avec ConnectMQ
Vous pouvez tester MQTT sur WebSocket dès maintenant avec l'endpoint du serveur MQTT public gratuit, wss://broker.connectmq.com:8084/mqtt. Lorsque vous êtes prêt à construire un vrai tableau de bord, inscrivez-vous gratuitement sur app.connectmq.com (offre Serverless gratuite, sans carte bancaire), créez un broker MQTT managé et connectez-vous avec vos propres nom d'utilisateur, mot de passe et client ID. Le client MQTT intégré au portail et l'explorateur de topics en temps réel permettent de vérifier facilement que votre application web publie bien ce que vous attendez.
Questions fréquentes
Quel port utilise MQTT sur WebSocket ?
Il n'existe pas de port standard unique. Sur broker.connectmq.com, le WebSocket non chiffré utilise le port 8083 et le WebSocket sécurisé le port 8084, tous deux avec le chemin /mqtt.
MQTT sur WebSocket est-il plus lent que MQTT sur TCP ?
La surcharge est faible. Après la mise à niveau HTTP initiale, chaque paquet MQTT est encapsulé dans une trame WebSocket qui n'ajoute que quelques octets : pour la plupart des applications, la latence reste proche de celle du TCP brut.
Ai-je besoin d'un serveur backend pour utiliser MQTT dans le navigateur ?
Non. Avec MQTT sur WebSocket, le navigateur se connecte directement au broker. Un backend n'est nécessaire que si vous voulez garder les identifiants hors du client ou ajouter votre propre logique métier.
Le CORS s'applique-t-il à MQTT sur WebSocket ?
Non, les connexions WebSocket ne sont pas soumises aux requêtes préliminaires CORS comme le sont les requêtes fetch et XHR. Si une connexion échoue, vérifiez plutôt l'URL, le port, le chemin et les identifiants.
Les clients navigateur et les appareils ESP32 peuvent-ils partager les mêmes topics ?
Oui. Le broker achemine les messages par topic quel que soit le transport : un navigateur en WSS et un appareil en TCP sur le port 1883 peuvent publier et s'abonner aux mêmes topics. Consultez le tutoriel ESP32 MQTT pour la partie appareil.



