Go MQTT客户端订阅失败返回nil,无法获取EMQ的suback如何解决?
问题原因
- 常用的Go MQTT客户端库
eclipse/paho.mqtt.golang中,Subscribe方法返回的Token的Error()方法仅会在传输/协议层出现错误时返回非空值,比如网络中断、客户端未完成连接、订阅请求超时这类问题。服务端返回的SUBACK报文中的失败原因码(你遇到的128属于通用订阅失败码)属于业务层面的订阅结果,不会被写入Token.Error(),所以原有判断逻辑抓不到这类订阅失败场景。 - 原有代码中
Subscribe的第三个参数传了nil,也没有主动读取SUBACK的返回字段,自然无法拿到服务端的拒绝原因。
解决方法
方法1:通过SubscribeToken的Result()方法读取订阅结果
将返回的通用Token断言为SubscribeToken类型,直接读取每个订阅主题对应的返回码判断是否成功:
import "github.com/eclipse/paho.mqtt.golang" // 修改后的订阅逻辑 token := c.Subscribe("go-mqtt/sample", 0, nil) if token.Wait() && token.Error() != nil { fmt.Println("订阅请求出错:", token.Error()) os.Exit(1) } // 额外校验服务端返回的订阅结果 if subToken, ok := token.(mqtt.SubscribeToken); ok { reasonCode := subToken.Result()["go-mqtt/sample"] // 0/1/2分别对应QoS0/1/2订阅成功,大于2均为订阅失败 if reasonCode > 2 { fmt.Printf("订阅被服务端拒绝,原因码:%d\n", reasonCode) os.Exit(1) } }
方法2:批量订阅场景的校验逻辑
如果同时订阅多个主题,可遍历返回结果逐个校验:
filters := map[string]byte{ "topic1": 0, "topic2": 1, } token := c.SubscribeMultiple(filters, nil) token.Wait() if token.Error() != nil { fmt.Println("订阅请求出错:", token.Error()) os.Exit(1) } subToken := token.(mqtt.SubscribeToken) for topic, code := range subToken.Result() { if code > 2 { fmt.Printf("主题[%s]订阅失败,原因码:%d\n", topic, code) } }
你遇到的128是MQTT协议定义的通用订阅失败码,常见触发原因包括主题名格式非法、客户端无对应主题的订阅权限、服务端主题数量超限等,可到EMQX的运行日志中查询更具体的拒绝原因。
内容的提问来源于stack exchange,提问作者huanxs
相关产品推荐
相关产品推荐

