react和fastapi实时通信示例

由于时效问题,该文某些代码、技术可能已经过期,请注意!!!本文最后更新于:10 个月前

使用websocket打通 react 和 fastapi

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React, { useEffect, useState } from "react";
import io from "socket.io-client";


const Monitor() = () => {
const [cpuUsage, setCpuUsage] = useState("");
const socketRef = React.useRef(null); // Socket引用


useEffect(() => {
socketRef.current = io("http://127.0.0.1:1080"); // 替换为FastAPI服务器的地址

socketRef.current.on("cpu_usage", (data) => { // 监听 "cpu_usage" 事件
setCpuUsage(data);
});

socketRef.current.on("connect", () => { // 启动监控
socketRef.current.emit("start_cpu_monitor");
});

return () => {
socketRef.current.emit("stop_cpu_monitor");
socketRef.current.disconnect(); // 在组件卸载时关闭Socket连接
};
}, []);

return (
<div className="child1-content">
<p>CPU Usage: {cpuUsage}</p>
</div>
);
};

export default Monitor;


后端代码 test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import sys
import socketio
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
import psutil

app = FastAPI()

sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
socket_app = socketio.ASGIApp(sio, static_files={
'/': './react-socketio/build'
})

app.mount("/", socket_app)


@sio.event
async def connect(sid, environ):
print('connected', sid)
cpu_percent = psutil.cpu_percent(interval=1) # 获取初始CPU使用率
print('Initial CPU Usage:', cpu_percent) # 打印初始CPU使用率
await sio.emit('cpu_usage', cpu_percent) # 推送初始CPU使用率给前端


@sio.event
async def disconnect(sid):
print('disconnected', sid)


async def cpu_monitor():
while running:
cpu_percent = psutil.cpu_percent(interval=1)
await sio.emit('cpu_usage', cpu_percent)
await sio.sleep(1)


@sio.on('start_cpu_monitor')
async def start_cpu_monitor(sid):
print('Starting CPU monitor...')
global running
running = True
sio.start_background_task(cpu_monitor) # 后台任务用于持续获取CPU使用率


@sio.on('stop_cpu_monitor')
async def stop_cpu_monitor(sid):
print('Stopping CPU monitor...')
global running
running = False


if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=8000)

后端启动命令

1
uvicorn test:app --reload --host 127.0.0.1 --port 1080

PS:上述后端代码中 socket_app 是挂载在根目录的,这样如果fastapi有其他路由,前端请求会404。所以要解决这个问题,socket_app 就不能挂载在根目录

修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import sys
import socketio
from fastapi import FastAPI, BackgroundTasks, Request
from fastapi.staticfiles import StaticFiles
import psutil


app = FastAPI()
sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
socket_app = socketio.ASGIApp(sio)

app.mount("/ws", socket_app)

@sio.event
async def connect(sid, environ):
print('connected', sid)
cpu_percent = psutil.cpu_percent(interval=1) # 获取初始CPU使用率
virtual_memory = psutil.virtual_memory()
memory_percent = virtual_memory.percent
print('Initial CPU Usage:', cpu_percent) # 打印初始CPU使用率
print('Initial Memory Usage:', memory_percent)
data = {
'cpu_percent': cpu_percent,
'memory_percent': memory_percent
}
await sio.emit('usage', data) # 推送初始CPU使用率给前端


@sio.event
async def disconnect(sid):
print('disconnected', sid)


async def monitor():
global running
while running:
cpu_percent = psutil.cpu_percent(interval=1)
virtual_memory = psutil.virtual_memory()
memory_percent = virtual_memory.percent
data = {
'cpu_percent': cpu_percent,
'memory_percent': memory_percent
}
await sio.emit('usage', data)
await sio.sleep(1)


@sio.on('start_monitor')
async def start_monitor(sid):
print('Starting System monitor...')
global running
running = True
sio.start_background_task(monitor) # 后台任务用于持续获取CPU使用率


@sio.on('stop_monitor')
async def stop_monitor(sid):
print('Stopping System monitor...')
global running
running = False


@app.get("/aichat")
async def aiChat(request: Request):
return {"message": "Hello, AI Chat!"}

if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=8000)

前端连接代码:注意这里的路径是 /ws/socket.io

1
socketRef.current = io("http://183.232.150.130:1080", {path:'/ws/socket.io', autoConnect: true});

参考:https://github.com/tiangolo/fastapi/issues/3666

1
2
3
4
if app.mount('/ws') in server
the client need sio.connect(url, socketio_path='/ws/docket.io')

So strange