Реализация Socketio с помощью FastApi и React

#python #reactjs #websocket #socket.io #fastapi

#python #reactjs #websocket #socket.io #fastapi

Вопрос:

У меня есть следующий techstack

  1. FastApi — серверная часть
  2. React — интерфейс

и хотите реализовать socketio (а не Websockets, предоставляемые FastApi). В нем отсутствует документация как в FastApi, так и в Socketio

Ответ №1:

По мере необходимости мы используем 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)
 

Дважды проверьте происхождение cors. Также вы можете добавить другие обработчики, используя socket_manager.on .

 #main.py

from socket import 

app = FastAPI(...)
socket_manager.mount_to("/ws", app)
 

Реализация интерфейса
Базовый код для интеграции так же прост, как

 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) });
 

Для моего проекта я создал контекст для этого следующим образом

 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)
}
 

Теперь, чтобы, наконец, отправить сообщение с вашего сервера клиенту, вы можете сделать

 socket_manager.send("Hello World")
 

Моменты, на которые стоит обратить внимание

  • Происхождение CORS должно быть точно таким же, если оно http://localhost:3000 из интерфейса, то это должно быть http://localhost:3000 и не http://localhost:3000 /. Ищите обратную косую черту
  • Также в документации socketio указано transports: ['websocket', 'polling'] значение по умолчанию, но когда я удаляю это. Это выдает мне ошибку cors. Документация может устареть.

Комментарии:

1. Следуя вашему примеру, я получаю эту ошибку: невозможно импортировать имя ‘socket’ из частично инициализированного модуля ‘socket’: S

2. @MichaelPaccione я ничего не могу вам сказать, не посмотрев на ваш код.

3. Я только что получил некоторую помощь и теперь разобрался