使用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

相关推荐
计算机毕设指导67 分钟前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
paopaokaka_luck24 分钟前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
傻啦嘿哟1 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
B站计算机毕业设计超人1 小时前
计算机毕业设计SparkStreaming+Kafka旅游推荐系统 旅游景点客流量预测 旅游可视化 旅游大数据 Hive数据仓库 机器学习 深度学习
大数据·数据仓库·hadoop·python·kafka·课程设计·数据可视化
捂月2 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
IT古董2 小时前
【人工智能】Python在机器学习与人工智能中的应用
开发语言·人工智能·python·机器学习
湫ccc2 小时前
《Python基础》之pip换国内镜像源
开发语言·python·pip
瓜牛_gn2 小时前
依赖注入注解
java·后端·spring
hakesashou2 小时前
Python中常用的函数介绍
java·网络·python
菜鸟的人工智能之路2 小时前
极坐标气泡图:医学数据分析的可视化新视角
python·数据分析·健康医疗