必须调用token.wait()或waittimeout()确认连接就绪,订阅需传非nil handler,qos=0消息可能因broker配置(如clean session=true)丢失,tls连接须正确配置证书验证。

connect() 后不加 token.Wait() 就发消息?必丢包
MQTT 客户端连接是异步的,client.Connect() 返回的是一个 token,不代表连接已就绪。跳过 token.Wait() 直接调用 publish() 或 subscribe(),大概率触发 panic: client is not connected,或静默失败——消息根本没发出去。
- 必须加
token.Wait(),但别在主线程死等;生产环境建议用token.WaitTimeout(5 * time.Second) - 检查错误不能只看
token.Error() != nil,还要确认token.Wait()返回值为 true,否则可能是超时未完成 - 搭配
opts.SetAutoReconnect(true)和OnConnectionLost回调,才能应对网络抖动
订阅时传 nil 作 handler?消息全被丢弃
client.Subscribe(topic, qos, nil) 看似简洁,实则埋雷:MQTT 库不会帮你注册默认回调,nil 表示“不处理收到的消息”,哪怕订阅成功,Message 对象也会被直接丢弃。
- 必须显式传入
MessageHandler函数,哪怕只是打印日志:func(client MQTT.Client, msg MQTT.Message) { fmt.Println(string(msg.Payload())) } - handler 内部不要做耗时操作(如 HTTP 请求、数据库写入),否则会阻塞整个 MQTT 事件循环;应把消息推到
chan后由 goroutine 异步处理 - 循环中订阅多个 topic 时,别在匿名函数里直接用循环变量
topic,要用局部副本,避免闭包捕获问题
qos=0 发出去了却收不到?不是丢包,是 broker 配置在“配合”你
client.Publish(topic, 0, false, payload) 看似简单,但实际送达高度依赖 broker 行为。所谓“假丢包”,常见于以下几种配置组合:
-
retain=false+clean session=true:若订阅者晚于发布者上线,broker 清除了历史消息,这条qos=0消息就真的消失了 - 测试阶段建议先用公共 broker(如
tcp://broker.hivemq.com:1883)排除本地配置问题 - 生产务必自建或托管 broker(如 EMQX),并确认其
allow_anonymous、max_connections等参数合理
用 TLS 连 mqtts 时,SetTLSConfig() 忘设证书验证?连都连不上
很多开发者照抄示例代码,只调 opts.SetTLSConfig(tlsConfig),却忘了 tlsConfig.InsecureSkipVerify = false(默认就是 false),结果连内网 EMQX 的自签名证书都通不过。
- 开发阶段可临时设
tlsConfig.InsecureSkipVerify = true快速验证逻辑,但上线前必须换回 CA 校验 - 加载证书要完整:CA 证书、客户端证书、私钥三者缺一不可;用
ioutil.ReadFile()读取后,需通过x509.NewCertPool()和tls.X509KeyPair()正确注入 - EMQX 默认开启
verify_client = true时,服务端还会校验客户端证书,此时SetUsername/SetPassword可能被忽略
真正卡住人的,从来不是“怎么连上”,而是“连上之后为什么收不到”——它往往藏在 token.Wait() 是否执行、handler 是否非空、qos 与 clean session 的隐式耦合里。这些点不手动验证一遍,光看日志永远以为是网络问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











