使用Websockets和FastAPI的简单聊天应用程序

原文链接: Simple chat application using Websockets with FastAPI

作者: Gealber Morales Gealber Morales

嘿,伙计们,我又在摆弄 FastAPI 了。这次我将尝试构建一个非常简单的聊天 Web 应用程序。我将使用 Websockets 和 FastAPI。

完整解释 Websockets 需要一篇文章,所以我假设读者对这个协议有一定的了解。这更像是 HTTP 的升级,而不是协议本身。

另一个有效的观点是,这是我修改 FastAPI 文档的结果。因此,我没有深入地教授更好的方法。在另一篇文章中,我将向您介绍一种更成熟的方法来解决这个问题。现在让我们享受学习的乐趣。

我们想要建立什么?对要求的部分描述

在我们开始编码之前,让我们先想想我们想要做什么。这个想法是建立一个简单的网页,模拟聊天室的行为。

期望的操作:

  • 在浏览器上打开页面。
  • 所有连接到同一 URL 的客户端,但通过不同的浏览器,可以在它们之间聊天。

行为的基本设计

客户端 1 和客户端 2 连接到URL,假设是 http://localhost:8000 。在此连接之后,来自客户端1的每个消息将被广播到房间上连接的其他客户端,在这种情况下将是客户端 2。因此,该模式的广义视图将如 ASCII 图片中所示:

lua 复制代码
  Client 1

     ___T_                              SERVER (FastAPI)
    | O O |                             +---------+
    |__n__|           Message 1         |         |
 >===]__o[===<    --------------->      |         |
     [o__]            Message 2         |         |
     ]| |[        <--------------       |         |
    [_| |_]                             |         |
                                        |         |
                                        |         | 
   Client 2                             |         |
                                        |         |
     ___T_                              |         |
    | O O |                             |         |
    |__n__|          Message 2          |         |
 >===]__o[===<   --------------->       |         |
     [o__]           Message 1          |         |
     ]| |[       <--------------        |         |
    [_| |_]                             +---------+

使用 go-asciibot 生成的机器人脚本

客户端 1 向服务器发送消息,服务器将消息广播给房间中的其他客户端。

依赖库

  • FastAPI
ruby 复制代码
$ pip install fastapi
  • Uvicorn
ruby 复制代码
$ pip install uvicorn

服务器代码

让我们进入代码。我将它分为两部分,一部分用于服务器代码,另一部分用于客户端代码。

正如我之前所说,我需要一个端点来服务 HTML 页面,在本例中,它将包含客户端代码。因此,我们需要学习如何使用 FastAPI 提供 HTML 。我们的 HTML 代码将在文件 index.html 上,与 main.py 在同一个文件夹中。

python 复制代码
from fastapi import FastAPI

app = FastAPI()

html = ""
with open('index.html', 'r') as f:
    html = f.read()

@app.get("/")
async def get():
    return HTMLResponse(html)

这是怎么回事首先,我们简单导入 FastAPI 类,以便能够创建我们的应用程序。接下来,我们读取 index.html 文件的内容,并将其内容存储在名为 html 的变量中。一定有更好的办法,但对我们来说,这解决了我们的问题。

你可能想知道 HTML 文件的内容是什么,我们会看到不要担心。

最后,我们定义我们的端点,在那里我们可以访问 index.html 文件的内容。这样,如果您访问http://localhost:8000,浏览器将呈现 HTML。

接下来怎么办?到目前为止,我们只能呈现 HTML 的内容,但我们还没有处理其他情况,对吗?如何区分一个客户和另一个客户?让我们解决这个问题。

python 复制代码
from typing import List
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

class ConnectionManager:
    def __init__(self):
        self.connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.connections.append(websocket)

    async def broadcast(self, data: str):
        for connection in self.connections:
            await connection.send_text(data)


manager = ConnectionManager()


@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    while True:
        data = await websocket.receive_text()
        await manager.broadcast(f"Client {client_id}: {data}")

名为 ConnectionManager 的类,顾名思义,是我们将要用来处理不同客户端连接的类。

  • 该类的 connect 方法,将 WebSocket 客户端作为参数。此客户端开始接受来自浏览器的消息,并添加到所有客户端的列表中。
  • broadcast 方法,将 message 作为参数,并将其内容广播给房间中的任何其他客户端。

每个客户端都将连接到 http://localhost:8000/ws/{client_id} ,其中 {client_id} 将是标识此客户端的整数。连接后,它将开始接收来自浏览器的消息。

此消息中的任何一条都将在稍后广播给房间中的任何客户端。

客户端代码

现在来看看客户端代码,在我们的例子中将是 HTML 代码。

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <button onClick="showForm(event)" id="connect">Connect</button>
        <form action="" onsubmit="sendMessage(event)" id="form" style="display: none">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var clientID = Date.now();
            var ws = new WebSocket(`ws://localhost:8000/ws/${clientID}`);

            function processMessage(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content);
                messages.appendChild(message);
            }

            ws.onmessage = processMessage;

            function sendMessage(event) {
                var input = document.getElementById("messageText")
                var message = document.createElement('li')
                var content = document.createTextNode(input.value)
                message.appendChild(content);
                messages.appendChild(message);
                ws.send(input.value);

                input.value = ''
                event.preventDefault()
            }

            function showForm(event) {
                var button = document.getElementById("connect");
                var form = document.getElementById("form");
                button.style.display = "none";
                form.style.display = "block";
            }

        </script>
    </body>
</html>

Ups!!这是一个很大的信息,所以让我们把它分块,并试图理解至少最重要的部分。纯 HTML 有两个主要组成部分,表单和按钮。

  • 按钮。单击后,按钮将对客户端隐藏,表单将可见。别再耍花招了。这是通过 showForm 方法上的 javascript 完成的。
  • 该表单包含一个用于写入消息的输入字段,以及一个将触发 JavaScript 端的方法 sendMessagesend 按钮。

按下 send 按钮后,我们将使用 WebSocket 连接将文本发送到服务器。通过这种方式,当服务器收到消息时,它会将其广播给房间中的任何其他客户端。

它怎么跑的?

shell 复制代码
uvicorn main:app --reload

--reload 标志是为了能够在失败时恢复,非常有用。

测试应用程序

打开至少两个 Web 浏览器并连接到 localhost:8000

相关推荐
炒空心菜菜19 分钟前
MapReduce 实现 WordCount
java·开发语言·ide·后端·spark·eclipse·mapreduce
(・Д・)ノ21 分钟前
python打卡day27
开发语言·python
小oo呆1 小时前
【学习心得】Jupyter 如何在conda的base环境中其他虚拟环境内核
python·jupyter·conda
小白学大数据2 小时前
Scrapy框架下地图爬虫的进度监控与优化策略
开发语言·爬虫·python·scrapy·数据分析
浊酒南街2 小时前
TensorFlow之微分求导
人工智能·python·tensorflow
立秋67892 小时前
用Python绘制梦幻星空
开发语言·python·pygame
alpszero2 小时前
YOLO11解决方案之对象裁剪探索
人工智能·python·计算机视觉·yolo11
wowocpp2 小时前
spring boot Controller 和 RestController 的区别
java·spring boot·后端
后青春期的诗go3 小时前
基于Rust语言的Rocket框架和Sqlx库开发WebAPI项目记录(二)
开发语言·后端·rust·rocket框架
freellf3 小时前
go语言学习进阶
后端·学习·golang