Uygulamalı Eğitimler

JavaScript ile MQTT: Node.js ve Tarayıcı için MQTT.js Eğitimi

MQTT.js v5 ile JavaScript’te MQTT: Node.js’te ve tarayıcıda WebSocket üzerinden bağlanma, abone olma ve publish, async/await, React ve hata yönetimi.

Güncellendi · 8 dk okuma

MQTT.js, JavaScript için en yaygın kullanılan MQTT client’ıdır. Aynı paket Node.js’te (TCP, TLS veya WebSocket üzerinden) ve tarayıcıda (WebSocket üzerinden) çalışır, MQTT 3.1.1 ve 5’i destekler ve 5. sürümden bu yana TypeScript tipleri ile promise tabanlı metotlarla birlikte gelir. Bu eğitim, v5 API’sini baştan sona ele alır.

MQTT.js’i kurun

bash
npm install mqtt

Örnekler ES modüllerini (import) ve herkese açık HiveMQ sandbox’ını kullanır. Bunları .mjs dosyaları olarak kaydedin veya package.json içinde "type": "module" ayarlayın.

Bağlantı URL’leri: hangi protokol nerede

URL şemasıTaşıma katmanıTipik portNode.jsTarayıcı
mqtt://Düz TCP1883EvetHayır
mqtts://TLS8883EvetHayır
ws://WebSocket8000, 8083, 80EvetYalnızca http:// sayfalarında
wss://Güvenli WebSocket8884, 8084, 443EvetEvet

Portlar ve WebSocket yolları broker’a göre değişir — HiveMQ veya EMQX sayfalarına bakın ya da MQTT portları rehberini okuyun.

Node.js’te abone olma ve publish etme

Klasik olay tabanlı API: mqtt.connect() hemen bir client döndürür ve bağlantı ilerledikçe olaylar yayar.

client.mjs
import mqtt from 'mqtt';

const topic = 'testmqtt/js-demo/hello';

const client = mqtt.connect('mqtt://broker.hivemq.com:1883', {
  clientId: `js-demo-${Math.random().toString(16).slice(2, 10)}`,
  clean: true,
  keepalive: 60,
  reconnectPeriod: 2000, // ms between reconnect attempts; 0 disables
  connectTimeout: 10_000,
});

client.on('connect', () => {
  console.log('connected');
  client.subscribe('testmqtt/js-demo/#', { qos: 1 }, (err) => {
    if (err) return console.error('subscribe failed:', err.message);
    client.publish(topic, JSON.stringify({ hello: 'world' }), { qos: 1 });
  });
});

client.on('message', (topic, payload, packet) => {
  console.log(`${topic} (retain=${packet.retain}): ${payload.toString()}`);
});

client.on('reconnect', () => console.log('reconnecting...'));
client.on('offline', () => console.log('offline'));
client.on('error', (err) => console.error('error:', err.message));

payload bir Buffer’dır — metin için toString(), JSON için JSON.parse(payload.toString()) çağırın. connect olayı her yeniden bağlanmadan sonra tekrar tetiklenir; clean: true ile broker aboneliklerinizi unutur, bu yüzden handler içinde abone olmak güvenli yöntemdir. MQTT.js ayrıca varsayılan olarak yeniden bağlandığında aboneliklerini yeniler (resubscribe: true).

connectAsync ile async/await

Script’ler, testler ve serverless fonksiyonlar için MQTT.js v5’teki promise API’si çok daha doğal okunur:

async.mjs
import mqtt from 'mqtt';

const client = await mqtt.connectAsync('mqtts://broker.hivemq.com:8883', {
  protocolVersion: 5,
});

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

try {
  const granted = await client.subscribeAsync('testmqtt/js-demo/#', { qos: 1 });
  console.log('granted:', granted.map((g) => `${g.topic} QoS ${g.qos}`).join(', '));

  await client.publishAsync('testmqtt/js-demo/async', 'sent with publishAsync', {
    qos: 1,
    retain: false,
  });

  await new Promise((resolve) => setTimeout(resolve, 2000));
} finally {
  await client.endAsync();
}

connectAsync(), client bağlanmadan önce bir error yaydığında — örneğin broker kimlik bilgilerinizi reddettiğinde — reject eder; böylece bunu normal bir try/catch ile ele alabilirsiniz. Erişilemeyen bir host için varsayılan olarak denemeye devam eder; bunun yerine hızlıca hata vermesi için üçüncü argüman olarak false geçin. publishAsync(), broker QoS 1 veya 2 mesajını onayladığında resolve olur. Her seviyenin neyi garanti ettiğini öğrenmek için MQTT QoS seviyeleri yazısına bakın.

MQTT.js mesajlarınızı canlı izleyin

Node.js’te TLS, kimlik bilgileri ve MQTT 5 seçenekleri

Production broker’ları TLS ve kimlik doğrulama gerektirir. Kimlik bilgileri bağlantı seçeneklerine girer; herkesçe güvenilen bir sertifikaya sahip broker için mqtts:// yeterlidir. Özel bir CA için CA sertifikasını (ve karşılıklı TLS için bir client sertifikası ile anahtarını) geçin:

secure.mjs
import { readFileSync } from 'node:fs';
import mqtt from 'mqtt';

const client = await mqtt.connectAsync('mqtts://broker.example.com:8883', {
  clientId: 'billing-service-01',
  username: process.env.MQTT_USERNAME,
  password: process.env.MQTT_PASSWORD,
  protocolVersion: 5,
  clean: false,
  properties: { sessionExpiryInterval: 3600 },
  // Only for a private CA / mutual TLS:
  // ca: readFileSync('ca.crt'),
  // cert: readFileSync('client.crt'),
  // key: readFileSync('client.key'),
  will: {
    topic: 'services/billing/status',
    payload: Buffer.from('offline'),
    qos: 1,
    retain: true,
  },
});

await client.publishAsync('services/billing/status', 'online', { qos: 1, retain: true });
await client.publishAsync('orders/created', JSON.stringify({ id: 42 }), {
  qos: 1,
  properties: {
    contentType: 'application/json',
    messageExpiryInterval: 60,
    userProperties: { source: 'billing' },
  },
});

Yerel testler dışında asla rejectUnauthorized: false ayarlamayın — sertifika doğrulamasını kapatır. Kimlik bilgilerini kaynak kodda değil, ortam değişkenlerinde tutun. will seçeneği, servis bağlantıyı kesmeden çökerse broker’ın publish edeceği bir Last Will kaydeder; retain: true ise en son durumu yeni abonelere açık tutar (bkz. retained mesajlar). MQTT 5 özelliklerine gerçekten ihtiyacınız olup olmadığı MQTT 5 ile 3.1.1 karşılaştırması yazısında ele alınıyor.

Temiz bir şekilde kapatma

Uzun süre çalışan bir Node.js servisi bağlantıyı düzgün biçimde kesmelidir; böylece işlemdeki QoS 1/2 mesajları tamamlanır ve broker normal bir yeniden başlatmada Last Will’inizi tetiklemez:

javascript
process.on('SIGTERM', async () => {
  await client.publishAsync('services/billing/status', 'offline', { qos: 1, retain: true });
  await client.endAsync();
  process.exit(0);
});

Tarayıcıda MQTT.js

Tarayıcıda yalnızca WebSocket URL’leri çalışır. HTTPS bir sayfada wss:// kullanmanız gerekir; aksi hâlde tarayıcı bağlantıyı mixed content (karışık içerik) olarak engeller:

browser.js
import mqtt from 'mqtt';

const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
  clientId: `web-${crypto.randomUUID().slice(0, 8)}`,
});

client.on('connect', () => client.subscribe('testmqtt/js-demo/#'));
client.on('message', (topic, payload) => {
  const li = document.createElement('li');
  li.textContent = `${topic}: ${payload.toString()}`;
  document.querySelector('#messages').append(li);
});

Vite, webpack 5 ve Next.js derleyicisi gibi modern bundler’lar, import mqtt from 'mqtt' yazdığınızda tarayıcı build’ini otomatik seçer. Bir bundler Node yerleşik modülleri hakkında hata verirse, bunun yerine hazır paketi mqtt/dist/mqtt.min.js üzerinden import edin. Bundler olmadan aynı dosyayı bir CDN’den <script> etiketiyle yükleyip global mqtt nesnesini kullanın. WebSocket üzerinden MQTT rehberi yolları ve portları ayrıntılı olarak ele alır.

React’te MQTT.js kullanımı

En yaygın hata, her render’da yeni bir client oluşturmaktır. Client’ı useEffect içinde bir kez oluşturun ve cleanup’ta mutlaka sonlandırın — React StrictMode geliştirme ortamında effect’leri iki kez mount eder; cleanup olmadan yinelenen bağlantılar ve yinelenen mesajlar alırsınız:

useMqtt.ts
import { useEffect, useState } from 'react';
import mqtt from 'mqtt';

export function useMqttMessages(url: string, topic: string) {
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    const client = mqtt.connect(url);
    client.on('connect', () => client.subscribe(topic));
    client.on('message', (_t, payload) => {
      setMessages((prev) => [...prev.slice(-99), payload.toString()]);
    });
    return () => {
      client.end();
    };
  }, [url, topic]);

  return messages;
}

Next.js’te MQTT.js tarayıcı API’lerini kullandığı için onu yalnızca Client Component’lerden ('use client') veya mqtt:// ya da mqtts:// kullanan sunucu tarafı route handler’lardan çağırın. Daha büyük uygulamalarda tek bir client’ı bir context provider’a koyup paylaşın.

Hata yönetimi

  • Her zaman bir error listener’ı ekleyin. Node.js’te işlenmemiş bir error olayı process’i çökertir.
  • Hatalı kimlik bilgileri yeniden denemeye devam eder. Olay API’sinde reddedilen bir CONNECT error yayar ve MQTT.js yeniden bağlanmaya devam eder. err.code değerini inceleyin ve yeniden denemek anlamsızsa client.end() çağırın. Kodları MQTT reason code aracı ile sorgulayın.
  • Hemen ardından bağlantı kopmasıyla gelen sonsuz yeniden bağlanma döngüleri genellikle yinelenen bir client ID’si veya aboneliğinizi reddeden bir ACL anlamına gelir. MQTT bağlantı hataları rehberine bakın.
  • Çevrimdışı tamponlama. Bağlantı yokken MQTT.js publish’leri bellekte kuyruğa alır ve yeniden bağlandığında gönderir. Eskimiş QoS 0 verisinin bunun yerine atılmasını istiyorsanız queueQoSZero: false ayarlayın.

Kendi broker’ınız için bir başlangıç noktası mı arıyorsunuz? MQTT kod üreteci bu kodu host’unuz, portunuz, kimlik bilgileriniz ve topic’iniz için oluşturur — ardından online MQTT client’ında canlı olarak test edin.

Sıkça sorulan sorular

MQTT.js tarayıcıdan 1883 portuna bağlanabilir mi?

Hayır. Tarayıcılar ham TCP soketi açamaz; bu nedenle tarayıcıdaki MQTT.js, broker’ın WebSocket listener’ını gösteren bir ws:// veya wss:// URL’si kullanmak zorundadır, örneğin wss://broker.hivemq.com:8884/mqtt. Node.js’te mqtt://, mqtts://, ws:// veya wss:// kullanabilirsiniz.

MQTT.js ile async/await nasıl kullanılır?

MQTT.js v5 promise tabanlı metotlar sunar: bağlanmak için mqtt.connectAsync(), dönen client üzerinde ise client.subscribeAsync(), client.publishAsync() ve client.endAsync(). Gelen mesajlar yine message olayı üzerinden iletilir.

React uygulamam neden iki MQTT bağlantısı açıyor?

React StrictMode geliştirme ortamında bileşenleri iki kez mount eder; bu nedenle cleanup içermeyen ve bağlantı kuran bir effect iki client oluşturur. Client’ı useEffect içinde oluşturun ve cleanup fonksiyonunda client.end() çağırın ya da tek bir client’ı bir modülde veya context’te tutun.