news 2026/3/16 8:51:10

ComfyUI WebSocket 实战:构建高效实时交互界面的技术解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ComfyUI WebSocket 实战:构建高效实时交互界面的技术解析


背景与痛点:轮询的“老毛病”

第一次把 ComfyUI 塞进网页里做实时预览,我图省事直接上了setInterval:每 500 ms 发一次 GET,把画布状态拉回来。
结果本地调试挺欢,一上公网立刻翻车:

  • 浏览器疯狂打转,F12 里全是 304
  • 手机端发热,流量像漏水
  • 后端日志 1 分钟刷出 3 万行,NGINX 直接 502

痛点一句话:轮询=假装实时,高延迟+高负载双杀
WebSocket 正好反着来:一次握手,全双双工,服务器有消息再推,省流量、省 CPU、真·实时。

技术选型:REST 与 WebSocket 的“擂台赛”

维度REST(轮训)WebSocket
连接数每次新建 TCP,+TLS 三次握手一次 TCP,长驻内存
头部开销每次 800 B+帧头 2 B
延迟≥ 1 RTT × 轮询间隔≤ 1 RTT
服务端推送做不到天生支持
反向代理无脑缓存需配置proxy_ws
代码复杂度中(要处理重连、心跳)

结论:纯展示用 REST 够;只要带“实时”二字,WebSocket 就是底线

核心实现:ComfyUI 里“长”出一条 WebSocket

下面代码基于 ComfyUI 0.2.0,Python 3.10,前端用原生 ES Module,无框架依赖。
目录结构:

comfyui-websocket-demo/ ├── server/ │ ├── websocket_node.py // 自定义节点 │ └── ws_server.py // 独立 ws 服务 └── ui/ └── websocket_client.js // 页面脚本

1. 后端:独立 WebSocket 服务

# ws_server.py import asyncio import json import websockets from comfyui_execution_queue import prompt_queue # ComfyUI 内部队列 CLIENTS = set() async def register(websocket): CLIENTS.add(websocket) await websocket.send(json.dumps({"type": "hello", "msg": "ComfyUI WS Ready"})) async def unregister(websocket): CLIENTS.discard(websocket) async def handler(websocket): await register(websocket) try: async for msg in websocket: data = json.loads(msg) if data["type"] == "prompt": # 把前端传来的工作流塞进 ComfyUI 队列 prompt_id = prompt_queue.put(data["workflow"]) await websocket.send(json.dumps({"type": "queued", "id": prompt_id})) except websockets.exceptions.ConnectionClosedOK: pass finally: await unregister(websocket) # 广播函数:ComfyUI 节点执行完会回调这里 async def broadcast_update(message: dict): if CLIENTS: await asyncio.gather(*(ws.send(json.dumps(message)) for ws in CLIENTS)) start_server = websockets.serve(handler, "0.0.0.0", 8188) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()

2. 自定义节点:把执行结果推出去

# websocket_node.py from nodes import NODE_CLASS_MAPPINGS from ws_server import broadcast_update class WebSocketSender: @classmethod def INPUT_TYPES(cls): return {"required": {"images": ("IMAGE",)}} RETURN_TYPES = () FUNCTION = "send" CATEGORY = "websocket" def send(self, images): # 取第一张图转 base64 from PIL import Image import base64, io img = Image.fromarray(images[0].cpu().numpy()) buf = io.BytesIO() img.save(buf, format="PNG") b64 = base64.b64encode(buf.getvalue()).decode() asyncio.run(broadcast_update({"type": "preview", "payload": bgt})) return {} NODE_CLASS_MAPPINGS["WebSocketSender"] = WebSocketSender

把上面两个文件扔进custom_nodes,重启 ComfyUI,WS 服务就挂在 8188 端口。

3. 前端:两行代码重连,三行代码渲染

<!-- index.html 片段 --> <canvas id="preview"></canvas> <script type="module" src="ui/websocket_client.js"></script>
// websocket_client.js const canvas = document.getElementById('preview'); const ctx = canvas.getContext('2d'); const wsUrl = `ws://${location.hostname}:8188`; let ws, reconnectTimer; function connect() { ws = new WebSocket(wsUrl); ws.binaryType = 'blob'; ws.onopen = () => console.log('[WS] 握手成功'); ws.onmessage = (e) =>厚实的知识点内容必须丰富到1000字左右及以上,绝不允许内容偏少。如原文内容不满,请主动结合实际经验、相关原理、应用场景等多角度补充和拓展,确保内容完整详实,表达清晰。 鼓励将中间内容分为多个小段落展示,每段可采用“1. 2. 3. 4. ...”等序号进行markdown格式的分点描述。每个点可聚焦一个具体细节、要点或流程,包括但不限于:项目背景、主要功能实现、关键步骤讲解、遇到的难点及应对、常见问题分析、优化思路、实际应用案例、经验总结和拓展方向等。通过分点方式,将复杂流程细致拆分,便于补充和扩充字数,让内容更加结构化且易于理解。 如发现内容长度明显不足,可以从如下维度适当增加说明:任务背景和意义、功能划分和实现逻辑、每一步的操作思路、常见易错点与解决方法、相关技术的经验分享、实际应用中遇到的案例或收获、优化建议和未来可能拓展点等,力求让新手也能跟随说明掌握核心流程与知识点。 每一个分段建议主题清晰,按问题或环节“一段一事”展开叙述,便于读者逐步消化和理解,避免无序堆砌。 用通俗直白、易于理解的语言,讲清楚整个实现过程、背后的思路、涉及的重点细节,不要过度理论化,内容以实用为主。 所有描述须聚焦实际操作、项目实现、经验与总结,突出“原文亮点+实践体会”与“平台快速落地思路”两大核心,帮助内容自然扩展到1000字左右。 [![限时福利领取](https://i-operation.csdnimg.cn/images/9ff43b7cc421481c9ba7d33afa47045e.png)](https://t.csdnimg.cn/Y21s) ---
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/16 1:41:31

从零构建高可用Chatbot UI:React实战与WebSocket优化指南

电商客服场景里&#xff0c;用户问完“我的券在哪”后&#xff0c;往往三秒内就想看到答案&#xff1b;大促高峰每秒上千条咨询&#xff0c;页面既要保证毫秒级响应&#xff0c;又得让客服无缝接管&#xff1b;一旦掉线重连导致记录丢失&#xff0c;投诉单就会像雪片一样飞来—…

作者头像 李华
网站建设 2026/3/13 13:14:56

图像处理毕业设计选题指南:从零构建一个可扩展的图像水印系统

图像处理毕业设计选题指南&#xff1a;从零构建一个可扩展的图像水印系统 大四下学期&#xff0c;最怕的就是“选题卡壳”。图像处理方向听起来高大上&#xff0c;可真到动手时&#xff0c;要么发现 GitHub 上的 SOTA 模型跑不动&#xff0c;要么老师一句“工作量不够”直接打…

作者头像 李华
网站建设 2026/3/11 14:20:35

Coqui TTS 下载与部署实战:提升语音合成效率的最佳实践

背景痛点&#xff1a;官方下载为何“卡”在第一步 Coqui TTS 的模型仓库托管在 GitHub Release Zenodo 双源&#xff0c;单个语音包 300 MB&#xff5e;1.2 GB 不等。 在 10 Mbps 出口带宽的 CI 机器上&#xff0c;默认 TTS().load_model("tts_models/en/ljspeech/tacot…

作者头像 李华