Comfy UI远程WebSocket API调用失败求助(ngrok/cloudflared转发无效)
问题
服务器运行Comfy UI服务,本地通过WebSocket调用其API时失败。本地调用localhost完全正常,但使用ngrok或cloudflared转发的服务器地址时出现握手错误,请求技术解决。
代码示例
#This is an example that uses the websockets api to know when a prompt execution is done #Once the prompt execution is done it downloads the images using the /history endpoint import websocket #NOTE: websocket-client (https://github.com/websocket-client/websocket-client) import uuid import json import urllib.request import urllib.parse import requests server_address = "badf-95-7-52-49.ngrok-free.app" client_id = str(uuid.uuid4()) def queue_prompt(prompt): p = {"prompt": prompt, "client_id": client_id} data = json.dumps(p).encode('utf-8') req = urllib.request.Request("http://{}/prompt".format(server_address), data=data) return json.loads(urllib.request.urlopen(req).read()) def get_image(filename, subfolder, folder_type): data = {"filename": filename, "subfolder": subfolder, "type": folder_type} url_values = urllib.parse.urlencode(data) with urllib.request.urlopen("http://{}/view?{}".format(server_address, url_values)) as response: return response.read() # def set_image def get_history(prompt_id): with urllib.request.urlopen("http://{}/history/{}".format(server_address, prompt_id)) as response: return json.loads(response.read()) def get_images(ws, prompt): prompt_id = queue_prompt(prompt)['prompt_id'] output_images = {} while True: out = ws.recv() if isinstance(out, str): message = json.loads(out) if message['type'] == 'executing': data = message['data'] if data['node'] is None and data['prompt_id'] == prompt_id: break #Execution is done else: continue #previews are binary data history = get_history(prompt_id)[prompt_id] for o in history['outputs']: for node_id in history['outputs']: node_output = history['outputs'][node_id] if 'images' in node_output: images_output = [] for image in node_output['images']: image_data = get_image(image['filename'], image['subfolder'], image['type']) images_output.append(image_data) output_images[node_id] = images_output return output_images def upload_file(file, subfolder="", overwrite=False): try: # Wrap file in formdata so it includes filename body = {"image": file} data = {} if overwrite: data["overwrite"] = "true" if subfolder: data["subfolder"] = subfolder resp = requests.post(f"http://{server_address}/upload/image", files=body,data=data) if resp.status_code == 200: data = resp.json() # Add the file to the dropdown list and update the widget value path = data["name"] if "subfolder" in data: if data["subfolder"] != "": path = data["subfolder"] + "/" + path else: print(f"{resp.status_code} - {resp.reason}") except Exception as error: print(error) return path #load workflow from file with open("workflow3.json", "r", encoding="utf-8") as f: workflow_data = f.read() workflow = json.loads(workflow_data) #set the text prompt for our positive CLIPTextEncode #random seed import random seed = random.randint(1, 1000000000) #set the image url workflow["7"]["inputs"]["url"] = "https://i.hizliresim.com/6fy279d.jpg" workflow["8"]["inputs"]["url"] = "https://media.licdn.com/dms/image/D4D03AQGev1Jwi8TzCQ/profile-displayphoto-shrink_800_800/0/1713355416560?e=2147483647&v=beta&t=iiz8OYnb-lKz2pmpT0STkvTR3yShXWscYAW-6nJ1nXU" ws = websocket.WebSocket() ws.connect("wss://requirements-mississippi-event-meeting.trycloudflare.com/".format(server_address, client_id)) images = get_images(ws, workflow) #Commented out code to display the output images: for node_id in images: for image_data in images[node_id]: from PIL import Image import io image = Image.open(io.BytesIO(image_data)) #image.show() # save image image.save(f"{node_id}-{seed}.png")
报错信息
Traceback (most recent call last): File "c:\Users\musta\OneDrive\Masaüstü\API\dreaminAI_websockets_api_example.py", line 126, in <module> ws.connect("wss://requirements-mississippi-event-meeting.trycloudflare.com/".format(server_address, client_id)) File "C:\Users\musta\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\websocket\_core.py", line 261, in connect self.handshake_response = handshake(self.sock, url, *addrs, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\musta\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\websocket\_handshake.py", line 65, in handshake status, resp = _get_resp_headers(sock) ^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\musta\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\websocket\_handshake.py", line 150, in _get_resp_headers raise WebSocketBadStatusException( websocket._exceptions.WebSocketBadStatusException: Handshake status 200 OK -+-+- {'date': 'Tue, 07 May 2024 19:33:36 GMT', 'content-type': 'text/html', 'transfer-encoding': 'chunked', 'connection': 'keep-alive', 'cf-ray': '8803a4855b60b3a7-MUC', 'cf-cache-status': 'DYNAMIC', 'accept-ranges': 'bytes', 'access-control-allow-origin': '*', 'last-modified': 'Sun, 14 Apr 2024 16:12:18 GMT', 'access-control-allow-credentials': 'true', 'access-control-allow-headers': 'Content-Type, Authorization', 'access-control-allow-methods': 'POST, GET, DELETE, PUT, OPTIONS', 'server': 'cloudflare'} -+-+- None
解决方案
1. 修复WebSocket连接地址错误
代码中WebSocket连接地址写死为固定值,未使用变量替换,且缺少Comfy UI的WebSocket端点/ws,导致请求返回HTML页面(握手200的原因)。修改为:
ws.connect(f"wss://{server_address}/ws?clientId={client_id}")
- 使用
f-string确保变量正确注入 - 必须添加
/ws路径,这是Comfy UI处理WebSocket请求的标准端点
2. 统一转发地址
代码中server_address用的是ngrok地址,但WebSocket连接用的是cloudflare地址,两者不匹配,需统一:
- 若用ngrok,所有HTTP/WebSocket请求都使用
badf-95-7-52-49.ngrok-free.app - 若用cloudflared,将
server_address替换为cloudflare生成的转发地址
3. 修正HTTP请求协议
转发地址默认是HTTPS协议,代码中所有HTTP请求仍用http://,会导致混合内容错误,需全部改为https://:
比如queue_prompt函数:
req = urllib.request.Request("https://{}/prompt".format(server_address), data=data)
get_image、get_history、upload_file中的地址也要同步修改。
4. 确保转发工具正确配置
- ngrok:启动命令为
ngrok http 8188(默认Comfy UI端口),无需额外参数,默认支持WebSocket - cloudflared:启动命令为
cloudflared tunnel --url http://localhost:8188,工具会自动处理WebSocket协议升级
5. 先验证转发地址可用性
在浏览器中访问https://<你的转发地址>,确认能打开Comfy UI界面;再用浏览器控制台执行new WebSocket('wss://<你的转发地址>/ws?clientId=test'),验证WebSocket连接是否正常。
内容的提问来源于stack exchange,提问作者mustafa zahter
相关产品推荐
相关产品推荐

