FastAPI独立应用无法结合Binance WebSocket监听与REST接口问题
问题分析与解决方案
核心问题
- 主线程阻塞:
connect_to_binance_websocket()中的ws.run_forever()是阻塞调用,直接在__main__中执行会卡住主线程,导致uvicorn.run()永远无法启动;而用uvicorn直接启动时,__main__代码块不会执行,WebSocket连接根本没建立,所以接口返回空。 - 变量名错误:回调函数中写了
last_trades += data,但全局变量是last_trade,而且应该用append()添加单条交易数据,不是+=。 - 交易对订阅错误:Binance的现货交易对是
btcusdt@trade,不是btctusd@trade,导致订阅不到数据。 - 线程安全风险:WebSocket回调在单独线程运行,FastAPI请求在异步线程处理,直接操作全局列表可能引发数据竞争。
- 返回值处理不当:FastAPI会自动序列化Python对象,手动用
json.dumps()会返回字符串而非JSON对象。
修改后的完整代码
import websocket import json import time import uvicorn from fastapi import FastAPI import threading from threading import Lock app = FastAPI() last_trades = [] LASTS = 100 trade_lock = Lock() # 线程安全锁 def on_message(ws, message): global last_trades data = json.loads(message) if 'e' in data and data['e'] == 'trade': with trade_lock: last_trades.append(data) if len(last_trades) > LASTS: last_trades.pop(0) def on_error(ws, error): print(f"WebSocket错误: {error}") def on_close(ws): print("WebSocket连接关闭") reconnect() def on_open(ws): ws.send(json.dumps({ "method": "SUBSCRIBE", "params": ["btcusdt@trade"], # 修正交易对 "id": 1 })) def reconnect(): delay = 5 print(f"{delay}秒后尝试重连...") time.sleep(delay) connect_to_binance_websocket() def connect_to_binance_websocket(): websocket_url = "wss://stream.binance.com:9443/ws" ws = websocket.WebSocketApp(websocket_url, on_message=on_message, on_error=on_error, on_close=on_close) ws.on_open = on_open ws.run_forever() # 启动时自动启动WebSocket后台线程 @app.on_event("startup") def startup_event(): ws_thread = threading.Thread(target=connect_to_binance_websocket, daemon=True) ws_thread.start() @app.get("/") async def get_last_trades(): with trade_lock: return {"last_100_trades": last_trades.copy()} # 返回副本避免外部修改 if __name__ == '__main__': uvicorn.run(app, host="0.0.0.0", port=8000)
关键修改说明
- 后台线程启动WebSocket:用
threading.Thread把WebSocket连接放到后台,避免阻塞主线程,同时通过startup事件确保uvicorn启动时自动初始化连接。 - 线程安全锁:用
Lock保护对last_trades的读写操作,避免多线程冲突。 - 修正变量名与数据添加方式:把
last_trades += data改为last_trades.append(data),确保单条交易数据正确加入列表。 - 修正交易对:将
btctusd@trade改为btcusdt@trade,正确订阅Binance的BTC/USDT交易数据。 - 优化返回值:直接返回Python字典,FastAPI自动序列化为JSON,同时返回列表副本避免外部修改原数据。
运行方式
无论是用python main.py还是uvicorn main:app --host 0.0.0.0 --port 8000启动,WebSocket都会自动建立连接,访问http://localhost:8000即可获取最近100条交易数据。
内容的提问来源于stack exchange,提问作者CrunchyFanch
相关产品推荐
相关产品推荐

