浏览器 MQTT 指南
MQTT、WebSocket 还是 MQTT over WSS?按责任选择
客户端需要 Broker Topic、QoS 和会话行为时选择 MQTT;浏览器与服务器只需一条自定义通道、且应用自行负责消息语义时选择原生 WebSocket;浏览器需要加入与设备相同的 MQTT Topic 与策略模型时选择 MQTT over WSS。
选择最小的完整模型
根据产品真正需要的消息责任来选择,而不是因为每种方案都能保持长连接。
选择原生 WebSocket
选择 MQTT over WSS
明确协议层与责任归属
MQTT over WSS 组合了多个协议;它既没有用 WebSocket 取代 MQTT,也没有把应用责任转移给传输层。
MQTT over TLS/TCP
适用于能够打开 TCP Socket 的原生设备与服务。
- 应用 Payload
- MQTT Topic、QoS、会话
- TLS → TCP
原生 WebSocket
适用于浏览器与应用服务器之间的自定义通道。
- 应用自定义消息与恢复逻辑
- WebSocket Frame
- TLS → TCP
MQTT over WSS
适用于连接 Broker 监听器的浏览器 MQTT 客户端。
- 应用 Payload
- MQTT Topic、QoS、会话
- WebSocket Frame
- TLS → TCP
| 责任边界 | MQTT | WebSocket | MQTT over WSS |
|---|---|---|---|
| 消息语义 | Broker Topic、QoS、保留消息与会话 | 应用自行定义路由、确认、重放与消息含义 | MQTT 语义封装在 WebSocket Frame 内,保持不变 |
| 身份与授权 | Broker Client 身份与发布/订阅策略 | 应用会话,以及对每个自定义消息操作的授权 | TLS 保护传输;Broker 身份与 Topic 策略仍然适用 |
| 断线恢复 | 客户端重连,并明确选择干净或持久 MQTT 会话行为 | 应用自行重建状态、订阅与漏失消息处理 | 先恢复 WSS,再重新连接 MQTT,并恢复或重建订阅 |
运行固定沙盒 MQTT.js 回环
此示例有意锁定为 RunMQTT 公共沙盒。只需把两个公共沙盒占位符替换为 Public Broker 页面当前展示的公共测试凭据。
import mqtt from "mqtt";
const endpoint = "wss://public.runmqtt.com/mqtt";
const suffix = crypto.randomUUID().replaceAll("-", "");
const topic = `runmqtt/sandbox/${suffix}/loopback`;
const payload = JSON.stringify({
source: "runmqtt-wss-guide",
value: 42,
});
const client = mqtt.connect(endpoint, {
clientId: `runmqtt-guide-${suffix}`,
username: "<PUBLIC_SANDBOX_USERNAME>",
password: "<PUBLIC_SANDBOX_PASSWORD>",
clean: true,
connectTimeout: 10_000,
reconnectPeriod: 3_000,
protocolVersion: 4,
});
client.on("connect", async () => {
await client.subscribeAsync(topic, { qos: 1 });
await client.publishAsync(topic, payload, { qos: 1 });
});
client.on("message", (_topic, _payload) => {
console.info("Synthetic QoS 1 loopback received");
});
client.on("reconnect", () => console.info("Reconnecting"));
client.on("close", () => console.info("Disconnected"));
client.on("error", () => console.error("MQTT connection failed"));
export async function disconnect() {
await client.endAsync();
}
window.addEventListener("pagehide", () => client.end(true));分别处理连接、重连与 MQTT 状态
WebSocket Upgrade 成功只是传输前提;客户端仍需完成 MQTT CONNECT,并恢复所需的订阅状态。
- 01
先连接 WSS,再连接 MQTT
验证公共 TLS 证书,把 /mqtt Upgrade 为 WebSocket,完成 MQTT 身份验证,并等待 MQTT Connect 事件后再订阅或发布。
- 02
重连并恢复业务意图
意外断开后,MQTT.js 会打开新的 WSS 通道并再次发送 MQTT CONNECT。使用 clean: true 时,应在 Connect Handler 中重新订阅。
- 03
主动断开连接
页面离开或用户停止会话时结束 MQTT Client,不要让重连计时器或隐藏订阅继续运行。
可复现的 RunMQTT 沙盒证据
验证于 2026-08-10 完成,使用 MQTT.js 5.15.2、MQTT 3.1.1,并启用证书验证。这些检查只证明所记录沙盒的兼容性,不代表性能结果或 SLA。
| 验证项目 | 结果 | 范围 |
|---|---|---|
| 浏览器 WSS 连接 | Chromium 142、Firefox 150 与 WebKit 26.4 均在未绕过 TLS 验证的情况下打开固定 WSS 端点。 | wss://public.runmqtt.com/mqtt |
| MQTT QoS 1 回环 | 普通 MQTT 1883、MQTT TLS 8883 与 WSS 443 均完成发布/订阅回环。 | 当前公共测试凭据与合成随机 Topic |
| Relay 防回归检查 | 五分钟健康检查要求 Cloudflare 与 Google DoH 都把公共域名解析到 Relay IP,然后验证证书名称、Relay 监听器、主机名匹配,以及真实的 /mqtt WebSocket Upgrade。 | 每五分钟执行一次的部署检查 |
根据运行时与消息契约选择传输
同一产品可以让设备使用 MQTT over TLS、浏览器控制台使用 MQTT over WSS,并让另一套应用专用实时 UI 使用原生 WebSocket。
| 场景 | 优先选择 | 原因 | 生产边界 |
|---|---|---|---|
| 浏览器 MQTT 控制台 | MQTT over WSS | 浏览器加入与其他 MQTT 客户端相同的 Topic、QoS 与 Broker 策略模型。 | 使用用户级或短期凭证;切勿把共享生产密钥写入前端代码。 |
| 移动网络客户端 | 原生应用使用 MQTT over TLS;浏览器运行时使用 MQTT over WSS | 选择运行时支持的传输,同时保留 MQTT 重连与 Topic 行为。 | 在真实网络切换中测试,并明确退避、会话与重复消息处理。 |
| 设备遥测 | MQTT over TLS/TCP | 原生设备发布经 Broker 路由的遥测时,通常不需要额外的 WebSocket Frame 层。 | 为每台设备分配唯一身份与最小权限发布策略。 |
| 命令下行 | MQTT | 相比自定义 Socket 通道,Broker 订阅、QoS 与会话选择能更直接地表达设备命令投递。 | 单独授权命令 Topic,并设计幂等的命令处理。 |
MQTT 与 WebSocket 常见问题解答
MQTT 和 WebSocket 是同一种协议吗?
不是。MQTT 定义了应用层消息语义。WebSocket 提供了一个持久的双向通道。MQTT 可以使用 WebSocket 作为其传输层之一。
浏览器可以直接连接到 MQTT 吗?
浏览器无法打开任意原始 TCP Socket。浏览器 MQTT 客户端通常通过 WSS 连接 Broker 的 WebSocket 监听器,并在 WebSocket Frame 中交换 MQTT 报文。
WSS 重连会自动恢复 MQTT 订阅吗?
不会自动恢复。WebSocket 只恢复通道;MQTT 客户端还必须重新连接,并依靠恢复的 MQTT 会话或重新订阅。沙盒示例使用干净会话,因此每次连接后都会重新订阅。
WebSocket 比 MQTT 快吗?
不存在负责任的通用答案。应比较完整应用路径,包括路由、授权、投递、恢复与实际网络;本指南不作任何性能或 SLA 声明。
继续落实下一层边界
先试用固定沙盒,再深入 MQTT 基础、生产安全与后端事件流边界。