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

如何正确连接含/不含SocketIO的Python FastAPI后端与React前端

问题定位

你看到的报错本质是两类问题叠加:

  • 请求URL拼接错误,出现重复协议头、路径多写/漏写问题,对应报错片段里{YOU MESS UP HERE}标注的异常位置
  • FastAPI侧CORS配置缺失、SocketIO挂载路径与前端配置不匹配,触发浏览器跨域拦截

8000是uvicorn启动FastAPI服务的默认端口,3000是React本地开发服务的默认端口,以下是两类场景的可直接复用的正确配置。


正确配置方案

场景1:纯FastAPI后端(无SocketIO服务)

后端配置

先安装依赖:
pip install fastapi uvicorn

核心代码如下,CORS配置必须正确声明允许的前端源:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# CORS核心配置
app.add_middleware(
    CORSMiddleware,
    # 本地开发填React服务地址,生产环境替换为实际前端域名
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 普通HTTP接口正常定义即可
@app.get("/api/health")
async def health_check():
    return {"status": "running"}

前端请求配置

用axios/fetch发请求时,基础地址直接写http://127.0.0.1:8000即可,不要重复拼接http://协议头,接口路径直接跟在基础地址后,比如请求健康检查接口的完整地址为http://127.0.0.1:8000/api/health。


场景2:FastAPI搭载python-socketio服务

SocketIO对接时路径对齐是核心,90%的连接失败都是前后端路径不匹配导致的。
先安装后端依赖:
pip install fastapi uvicorn python-socketio
前端安装客户端依赖:
npm install socket.io-client

挂载方式A:SocketIO走默认根路径

后端代码:

import socketio
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

# 初始化SocketIO服务,async_mode选asgi适配FastAPI
sio = socketio.AsyncServer(
    async_mode="asgi",
    # SocketIO单独配置CORS,和普通接口的CORS配置分开
    cors_allowed_origins="http://localhost:3000"
)
socket_app = socketio.ASGIApp(sio)
app = FastAPI()

# 普通HTTP接口的CORS正常配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 挂载SocketIO到根路径,不要加多余前缀
app.mount("/", socket_app)

# 普通接口正常定义
@app.get("/api/health")
async def health_check():
    return {"status": "running"}

# SocketIO事件监听
@sio.event
async def connect(sid, environ):
    print(f"客户端 {sid} 连接成功")

对应前端SocketIO初始化代码:

import { io } from "socket.io-client";

// 地址只写后端根地址,path使用默认值/socket.io即可,无需额外修改
const socket = io("http://127.0.0.1:8000", {
  transports: ["websocket", "polling"],
  withCredentials: true
});

挂载方式B:SocketIO走自定义子路径(如/ws前缀)

如果需要把WebSocket相关服务统一放到子路径下,必须保证前后端路径完全对齐,后端代码:

import socketio
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

sio = socketio.AsyncServer(
    async_mode="asgi",
    cors_allowed_origins="http://localhost:3000",
    # 核心:指定自定义socketio路径
    socketio_path="ws/socket.io"
)
socket_app = socketio.ASGIApp(sio, socketio_path="ws/socket.io")
app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 挂载路径前缀和socketio_path前缀保持一致
app.mount("/ws", socket_app)

# 普通接口、事件监听写法和之前一致
@app.get("/api/health")
async def health_check():
    return {"status": "running"}

@sio.event
async def connect(sid, environ):
    print(f"客户端 {sid} 连接成功")

对应前端初始化代码,path参数必须和后端完全一致:

import { io } from "socket.io-client";

const socket = io("http://127.0.0.1:8000", {
  // 路径前的斜杠不要漏,和后端配置的socketio_path完全对应
  path: "/ws/socket.io",
  transports: ["websocket", "polling"],
  withCredentials: true
});

排查清单
  • 先复制浏览器控制台报错里的完整请求URL,检查是否存在http://http://这类重复拼接协议头的问题,这类问题一般是封装请求实例时baseURL已经带了协议,拼接路径时又重复加了协议头导致的
  • CORS配置要覆盖两类服务:普通HTTP接口靠FastAPI的CORSMiddleware配置,SocketIO要在初始化AsyncServer时单独传cors_allowed_origins参数,不要漏配
  • SocketIO的path参数前后端必须100%匹配,不要多写、漏写斜杠,不要后端挂在/ws前缀下,前端还在用默认的/socket.io路径
  • 本地开发时不要混用127.0.0.1和localhost,CORS校验会严格匹配源,前端写的请求地址要和后端CORS允许的源完全一致

内容的提问来源于stack exchange,提问作者Maurice Pasternak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:15:47