You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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接口),同时删除阻塞式事件循环逻辑、移除浏览器环境不支持的模块导入。

  1. 修改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>
  1. 重写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:57:15