Flutter Web通过MQTT连接Azure IoT Hub失败,请求排查原因
我正在开发Flutter Web应用,需要对接Azure IoT Hub读取数据并在组件中展示。下面是我实现的MQTT连接逻辑代码:
class MqttHandler with ChangeNotifier { final ValueNotifier<String> data = ValueNotifier<String>(""); late MqttBrowserClient client; Future<Object> connect() async { client = MqttBrowserClient( 'ws://iothub.azure-devices.net', ''); client.port = 443; client.logging(on: true); client.onConnected = onConnected; client.onDisconnected = onDisconnected; client.onUnsubscribed = onUnsubscribed; client.onSubscribed = onSubscribed; client.onSubscribeFail = onSubscribeFail; client.pongCallback = pong; client.keepAlivePeriod = 60; client.logging(on: true); client.websocketProtocols = ['mqtts']; /// Set the correct MQTT protocol for mosquito client.setProtocolV311(); final MqttConnectMessage connectMessage = MqttConnectMessage() .authenticateAs('iothub.azure-devices.net/DEVICE01', 'SharedAccessSignature') .withClientIdentifier('DEVICE01') .keepAliveFor(60) .startClean(); client.connectionMessage = connectMessage; try { await client.connect(); } catch (e) { print('Exception: $e'); client.disconnect(); } if (client.connectionStatus!.state == MqttConnectionState.connected) { print('MQTT_LOGS::Azure client connected'); } else { print( 'MQTT_LOGS::ERROR Azure client connection failed - disconnecting, status is ${client.connectionStatus}'); client.disconnect(); return -1; } print('MQTT_LOGS::Subscribing to the test/lol topic'); const topic = 'devices/EZTRDEVICE01/messages/events/'; client.subscribe(topic, MqttQos.atMostOnce); client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) { final recMess = c![0].payload as MqttPublishMessage; final pt = MqttPublishPayload.bytesToStringAsString(recMess.payload.message); data.value = pt; notifyListeners(); print( 'MQTT_LOGS:: New data arrived: topic is <${c[0].topic}>, payload is $pt'); print(''); }); return client; } void onConnected() { print('MQTT_LOGS:: Connected'); } void onDisconnected() { print('MQTT_LOGS:: Disconnected'); } void onSubscribed(String topic) { print('MQTT_LOGS:: Subscribed topic: $topic'); } void onSubscribeFail(String topic) { print('MQTT_LOGS:: Failed to subscribe $topic'); } void onUnsubscribed(String? topic) { print('MQTT_LOGS:: Unsubscribed topic: $topic'); } void pong() { print('MQTT_LOGS:: Ping response client callback invoked'); } void publishMessage(String message) { const pubTopic = 'test/sample'; final builder = MqttClientPayloadBuilder(); builder.addString(message); if (client.connectionStatus?.state == MqttConnectionState.connected) { client.publishMessage(pubTopic, MqttQos.atMostOnce, builder.payload!); } } }
运行时出现以下错误日志:
-2024-02-02 17:42:43.068 -- SynchronousMqttBrowserConnectionHandler::internalConnect - pre sleep, state = Connection status is connecting with return code of noneSpecified and a disconnection origin of none
1-2024-02-02 17:42:48.121 -- SynchronousMqttBrowserConnectionHandler::internalConnect - post sleep, state = Connection status is connecting with return code of noneSpecified and a disconnection origin of none
1-2024-02-02 17:42:48.122 -- SynchronousMqttBrowserConnectionHandler::internalConnect failed
Exception: mqtt-client::NoConnectionException: The maximum allowed connection attempts ({3}) were exceeded. The broker is not responding to the connection request message (Missing Connection Acknowledgement?
1-2024-02-02 17:42:48.124 -- MqttConnectionHandlerBase::disconnect - entered
1-2024-02-02 17:42:48.124 -- MqttConnectionHandlerBase::_performConnectionDisconnect entered
1-2024-02-02 17:42:48.125 -- MqttConnectionKeepAlive::stop - stopping keep alive
MQTT_LOGS:: Disconnected
MQTT_LOGS::ERROR Azure client connection failed - disconnecting, status is Connection status is disconnected with return code of noneSpecified and a disconnection origin of solicited
MQTT_LOGS:: Disconnected
应用在Chrome中运行,使用了mqtt_browser_client.dart,已尝试将端口改为443,但问题依旧。请问可能的原因是什么?
WebSocket地址与协议错误
Azure IoT Hub的WebSocket MQTT连接必须使用加密的wss://协议,而非明文的ws://,且地址需要包含/websocket后缀,正确格式应为wss://{你的IoT Hub名称}.azure-devices.net/websocket。代码中使用ws://iothub.azure-devices.net会导致连接被服务端拒绝,无法获取ACK响应。认证参数格式错误
authenticateAs的第一个参数应为纯设备ID(如DEVICE01),而非iothub.azure-devices.net/DEVICE01;第二个参数必须是完整的Shared Access Signature(SAS)令牌字符串(格式类似SharedAccessSignature sr=xxx&sig=xxx&se=xxx),不能用占位符'SharedAccessSignature'。无效的认证信息会导致IoT Hub静默拒绝连接。WebSocket协议标识配置错误
client.websocketProtocols应设置为['mqtt'],而非['mqtts']。mqtts是TCP加密连接的标识,WebSocket场景下服务端仅识别mqtt协议,错误配置会导致服务端无法解析连接请求。设备状态异常
确保DEVICE01已在Azure IoT Hub中注册且状态为启用。未注册或被禁用的设备发起连接时,IoT Hub不会返回连接确认,直接导致连接超时失败。订阅主题设备ID不匹配
虽然不是连接失败的直接原因,但代码中订阅的主题devices/EZTRDEVICE01/messages/events/里的设备ID与客户端标识DEVICE01不一致,后续即便连接成功也无法接收数据,建议统一为devices/DEVICE01/messages/events/。
内容的提问来源于stack exchange,提问作者sai

