使用 FastApi 和 React 实现 Socketio

tar*_*ghs 5 python websocket socket.io reactjs fastapi

我有以下技术堆栈

  1. FastApi-后端
  2. 反应 - 前端

并想要实现socketio(不是FastApi提供的Websockets)。FastApi 和 Socketio 都缺乏文档

tar*_*ghs 13

根据需要,我们使用python-socketio作为后端套接字服务器,在 React 上我们将使用socket.io-client。安装后我们需要设置一个套接字服务器。

后端实施

# socket.py

def handle_connect(sid, environ):
    logger.info(f"Socket connected with sid {sid}")

class SocketManager:
    def __init__(self, origins: List[str]):
        self.server = socketio.AsyncServer(
            cors_allowed_origins=origins,
            async_mode="asgi",
            logger=True,
            engineio_logger=True,
        )
        self.app = socketio.ASGIApp(self.server)

    @property
    def on(self):
        return self.server.on

    @property
    def send(self):
        return self.server.send

    def mount_to(self, path: str, app: ASGIApp):
        app.mount(path, self.app)


socket_manager = SocketManager(settings.origins)
socket_manager.on("connect", handler=handle_connect)
Run Code Online (Sandbox Code Playgroud)

仔细检查你的 cors 来源。您还可以使用添加其他处理程序socket_manager.on

#main.py

from socket import 

app = FastAPI(...)
socket_manager.mount_to("/ws", app)
Run Code Online (Sandbox Code Playgroud)

前端实现 集成的基本代码非常简单

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

const socket = io("ws://localhost:8000", {{ path: "/ws/socket.io/", transports: ['websocket', 'polling'] }});
socket.on("connect", () => { console.log("Connected", socket.id) }); 
socket.on("response", () => { console.log("Response", socket.id) });  
socket.on("message", data => { console.log(data) });
Run Code Online (Sandbox Code Playgroud)

对于我的项目,我为此创建了一个上下文,如下所示

import React, { createContext, useContext, useEffect, useState } from 'react';

import { io } from "socket.io-client";
import { useToastContext } from './ToastContext';


export const SocketContext = createContext()


export const SocketProvider = ({ children, uri, options }) => {
    const [socketIo, setSocketIo] = useState()
    const { sendToast } = useToastContext();

    useEffect(() => {
        const socket = io(uri, options);
        socket.on("connect", () => { console.log("Connected", socket.id) });
        socket.on("response", () => { console.log("Response", socket.id) });
        socket.on("message", data => { 
            sendToast(data)
        });
        setSocketIo(socket)
    }, [])

    return (
        <SocketContext.Provider value={socketIo}>
            {children}
        </SocketContext.Provider>
    )
}

export const useSocket = () => {
    return useContext(SocketContext)
}
Run Code Online (Sandbox Code Playgroud)

现在最终要从服务器向客户端发送消息,您可以这样做

socket_manager.send("Hello World")
Run Code Online (Sandbox Code Playgroud)

值得注意的点

  • CORS 来源应该完全相同,如果前端是 http://localhost:3000 ,那么它应该是 http://localhost:3000 而不是http://localhost:3000/。寻找反斜杠
  • 另外,socketio 文档说transports: ['websocket', 'polling']这是默认的,但是当我删除它时。它给了我 cors 错误。文档可能已过时。