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
- 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-protocolemqtt. - Le broker répond
101 Switching Protocolset la connexion devient un WebSocket. - À 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:// | |
|---|---|---|
| Chiffrement | Aucun — identifiants et payloads en clair | TLS, comme HTTPS |
| Utilisable depuis une page HTTPS | Non (bloqué comme contenu mixte) | Oui |
| Proxys et pare-feu | Parfois perturbé | Passe généralement sur le port 443 |
| Usage type | Développement local uniquement | Tout 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 :
| Broker | ws:// | wss:// | Chemin |
|---|---|---|---|
| broker.hivemq.com | 8000 | 8884 | /mqtt |
| broker.emqx.io | 8083 | 8084 | /mqtt |
| test.mosquitto.org | 8080 | 8081 | n’importe lequel |
| mqtt.eclipseprojects.io | 80 | 443 | /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 :
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 :
listener 1883
protocol mqtt
listener 8080
protocol websocketsPour 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 :
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 — utilisezwss://. - Le handshake échoue immédiatement ? Vérifiez le chemin (
/mqttou aucun) et le sous-protocole. - Derrière un reverse proxy ? Nginx et les proxys similaires doivent transmettre les en-têtes
UpgradeetConnectionet 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.