Pyscript嵌入gmqtt发布MQTT消息 单文件正常嵌入后报错
问题根因
- 核心运行环境不兼容:本地运行时是原生CPython,拥有完整系统TCP socket权限,可直接通过1883端口走TCP协议连接MQTT broker。但PyScript底层基于Pyodide(WASM编译的Python运行时),运行在浏览器沙箱中,完全禁止原生TCP连接发起,仅支持浏览器开放的HTTP/WebSocket网络接口。你使用的
gmqtt库是纯TCP实现的MQTT客户端,没有WebSocket传输适配,根本无法在浏览器环境下建立连接。 - 事件循环冲突:本地代码中手动创建独立asyncio事件循环,调用
loop.run_until_complete()阻塞运行任务。但PyScript已经将asyncio事件循环和浏览器原生事件循环做了绑定适配,手动新建事件循环+阻塞调用会直接打断PyScript的运行调度,触发运行时错误。 - 依赖接口缺失:代码中导入的
signal、os部分底层接口是面向原生操作系统设计的,浏览器沙箱不存在系统进程信号、底层系统调用的对应实现,导入阶段就会触发异常。
修复方案
浏览器环境下使用MQTT必须走MQTT over WebSocket协议,连接对应broker开放的WS/WSS端口,同时代码要适配PyScript的运行规则,这里推荐两种可落地的实现方式:
方案1:替换为兼容浏览器环境的Python MQTT库(推荐)
放弃使用gmqtt,换成支持WebSocket传输、纯Python实现无原生依赖的paho-mqtt(2.0以上版本支持asyncio接口),同时删除阻塞式事件循环逻辑、移除浏览器环境不支持的模块导入。
- 修改HTML页面的依赖声明,替换gmqtt为paho-mqtt:
<!DOCTYPE html> <html> <head> <title>Publish MQTT</title> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <py-env> - paho-mqtt>=2.0.0 </py-env> </head> <body> <py-script src="publish.py"></py-script> </body> </html>
- 重写publish.py代码,适配PyScript运行规则与WebSocket连接要求:
import asyncio from paho.mqtt import client as mqtt_client # 注意:broker.hivemq.com的WebSocket服务端口为8000,原生TCP端口1883在浏览器中无法使用 BROKER_ADDR = "broker.hivemq.com" WS_PORT = 8000 TEST_TOPIC = "TEST/TIME" CLIENT_ID = "3232DZQ" async def mqtt_task(): # 初始化客户端,指定传输方式为WebSocket client = mqtt_client.Client( mqtt_client.CallbackAPIVersion.VERSION2, CLIENT_ID, transport="websockets" ) # 绑定回调函数 def on_connect(client, userdata, flags, rc, properties): print('Connected') client.subscribe('TEST/#', qos=0) def on_message(client, userdata, msg): print(f"Received msg from {msg.topic}: {msg.payload.decode()}") def on_disconnect(client, userdata, flags, rc, properties): print('Disconnected') def on_subscribe(client, userdata, mid, rc_list, properties): print('Subscribed to TEST/#') client.on_connect = on_connect client.on_message = on_message client.on_disconnect = on_disconnect client.on_subscribe = on_subscribe # 建立WebSocket连接 await client.connect(BROKER_ADDR, WS_PORT) client.loop_start() # 发布测试消息 client.publish(TEST_TOPIC, 'IZISIUIQY', qos=1) # 等待1秒确保消息发送、订阅流程完成 await asyncio.sleep(1) # 断开连接 await client.disconnect() # 禁止手动新建事件循环/调用run_until_complete阻塞线程,直接将任务提交到PyScript已运行的事件循环即可 asyncio.ensure_future(mqtt_task())
方案2:通过JS互操作调用浏览器端MQTT库
如果纯Python库存在兼容问题,可以直接在HTML中引入成熟的浏览器端MQTT JS库(如mqtt.js),通过Pyodide提供的JS/Python互调接口直接使用JS层的MQTT能力,这种方式网络层完全走浏览器原生实现,兼容性最好。
注意事项
- 所有网页端MQTT连接必须使用WebSocket/WSS协议,对应broker必须开放WS端口,原生TCP的1883、8883端口受浏览器安全策略限制,永远无法在网页中直接连接。
- PyScript环境中禁止手动创建独立asyncio事件循环、禁止调用阻塞式的事件循环运行方法,否则会直接导致页面卡死或运行时报错。
- 不要导入面向原生操作系统的模块(如
signal),这类模块依赖系统底层能力,在浏览器沙箱中没有对应实现。
内容的提问来源于stack exchange,提问作者BADR EL KHALYLY
相关产品推荐
相关产品推荐

