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

FastAPI独立应用无法结合Binance WebSocket监听与REST接口问题

问题分析与解决方案

核心问题

  1. 主线程阻塞:connect_to_binance_websocket()中的ws.run_forever()是阻塞调用,直接在__main__中执行会卡住主线程,导致uvicorn.run()永远无法启动;而用uvicorn直接启动时,__main__代码块不会执行,WebSocket连接根本没建立,所以接口返回空。
  2. 变量名错误:回调函数中写了last_trades += data,但全局变量是last_trade,而且应该用append()添加单条交易数据,不是+=。
  3. 交易对订阅错误:Binance的现货交易对是btcusdt@trade,不是btctusd@trade,导致订阅不到数据。
  4. 线程安全风险:WebSocket回调在单独线程运行,FastAPI请求在异步线程处理,直接操作全局列表可能引发数据竞争。
  5. 返回值处理不当: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 04:40:37