使用 Django 开发用于 HTTP 连接和应用程序请求的服务器很常见。 但是,在开发需要始终打开连接以进行双向连接的应用程序(如会议和聊天程序)时,使用 HTTP 连接效率低下。 在这种情况下,使用 WebSockets 是必不可少的。
通过使用 WebSockets,连接到该开放网络的所有用户都可以实时接收相关数据,这提供了一种在客户端和服务器之间建立双向连接的方法。 这是一个有状态的协议,这意味着在初始连接身份验证之后,客户端凭据被保存,并且在连接被破坏之前不需要进一步的身份验证。
在本教程中,我们将学习如何使用 Django 和 React 构建聊天应用程序。 在本教程之后,您应该更熟悉 WebSockets 在 Django 和 React 中的工作方式。 要继续阅读本文,您需要:
对Django的基本了解
已安装 Django v3.2
对 React 的基本了解
您可以在 GitHub 上 找到完整的应用程序。 让我们开始吧!
WebSocket 功能
如何在 Django 中使用 WebSocket
构建前端
测试应用程序
WebSocket 是一种双向协议,这意味着数据可以在客户端和服务器之间即时交换而不会中断。 同理,WebSockets 也被视为全双工通信。
WebSockets 不需要任何特定的浏览器即可工作; 所有浏览器都兼容。 WebSocket 是一个有状态的协议。 由于客户端凭据是在主连接验证后保存的,因此在连接丢失之前不需要再次进行额外的身份验证。
当你想用 WebSockets 做任何事情时, Django Channels 是必不可少的,所以继续使用以下命令安装它:
pip install channels
在本节中,我们将设置 Django 以使用 WebSockets,并将其与构建普通的 Django 应用程序进行比较。
感谢 Django Channels,在 Django 中使用 WebSockets 很简单。 您可以使用 Django Channels 构建一个 ASGI (异步服务器网关接口)服务器,之后您可以构建一个组,成员可以在其中即时互相发短信。 交流不是与特定用户,而是与一个组,任何数量的用户都可以加入。
创建一个包含项目所有代码的文件夹。 导航到您刚刚在终端上创建的文件夹并运行 startproject命令来创建一个新的 Django 项目:
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →
$ django-admin startproject chat .
现在,运行 $ python3 manage.py startapp app创建一个新的应用程序。
您需要让您的 Django 项目知道已经添加了一个新应用程序并且您安装了 Channels 插件。 您可以通过更新 chat/settings.py文件并添加 'app'到 INSTALLED_APPS列表。 它看起来像下面的代码:
# project/settings.py INSTALLED_APPS = [ ... 'channels', 'app', ]
在里面 settings.py文件,您应该设置配置以允许 Django 和 Django 通道通过消息代理相互连接。 为此,我们可以使用 Redis 之类的工具,但在此示例中,我们将坚持使用本地后端。 将以下代码行添加到您的 settings.py文件:
ASGI_APPLICATION = "chat.routing.application" #routing.py will handle the ASGI CHANNEL_LAYERS = { 'default': { 'BACKEND': "channels.layers.InMemoryChannelLayer" } }
在上面的代码中, ASGI_APPLICATION需要运行 ASGI 服务器并告诉 Django 在事件发生时该做什么。 我们将把这个配置放在一个名为 routing.py. 路由 Django Channels 类似于 Django URL 配置; 它选择将 WebSocket 请求发送到服务器时要运行的代码。
在您创建路由之前,我们将首先开发 消费者 。 在 Django Channels 中,消费者使您能够在代码中创建一组函数,这些函数将在事件发生时被调用。 它们类似于 views在姜戈中。
开发消费者,打开 app/文件夹,新建一个名为 consumers.py,并粘贴以下代码:
# app/consumers.py import json from asgiref.sync import async_to_sync from channels.generic.websocket import WebsocketConsumer class TextRoomConsumer(WebsocketConsumer): def connect(self): self.room_name = self.scope\['url_route'\]['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name # Join room group async_to_sync(self.channel_layer.group_add)( self.room_group_name, self.channel_name ) self.accept() def disconnect(self, close_code): # Leave room group async_to_sync(self.channel_layer.group_discard)( self.room_group_name, self.channel_name ) def receive(self, text_data): # Receive message from WebSocket text_data_json = json.loads(text_data) text = text_data_json['text'] sender = text_data_json['sender'] # Send message to room group async_to_sync(self.channel_layer.group_send)( self.room_group_name, { 'type': 'chat_message', 'message': text, 'sender': sender } ) def chat_message(self, event): # Receive message from room group text = event['message'] sender = event['sender'] # Send message to WebSocket self.send(text_data=json.dumps({ 'text': text, 'sender': sender }))
现在,我们可以创建将处理您刚刚创建的消费者的路由。 创建一个名为的新文件 routing.py并粘贴下面的代码,这将协调消费者:
from channels.routing import ProtocolTypeRouter, URLRouter # import app.routing from django.urls import re_path from app.consumers import TextRoomConsumer websocket_urlpatterns = [ re_path(r'^ws/(?P[^/]+)/$', TextRoomConsumer.as_asgi()), ] # the websocket will open at 127.0.0.1:8000/ws/ application = ProtocolTypeRouter({ 'websocket': URLRouter( websocket_urlpatterns ) , })
现在,让我们构建一个聊天应用程序的前端,该应用程序使用 WebSockets 连接到 Django 后端。 我们将使用 React 构建这部分,并 使用 MUI 添加样式 。
在您的终端中,导航到项目的根目录并运行以下命令以获取 React 的 Create React App 样板代码:
npx create-react-app frontend
下一个, cd进入 frontend/目录并运行以下命令来安装 MUI 和 WebSocket 依赖项,这允许我们将 React 应用程序连接到 WebSocket 服务器:
npm install --save --legacy-peer-deps @material-ui/core npm install websocket
删除所有代码 frontend/src/App.js. 我们将用本教程其余部分中的代码替换它,从初始状态开始:
import React, { Component } from 'react'; import { w3cwebsocket as W3CWebSocket } from "websocket"; class App extends Component { state = { filledForm: false, messages: [], value: '', name: '', room: 'test', } client = new W3CWebSocket('ws://127.0.0.1:8000/ws/' + this.state.room + '/'); //gets room_name from the state and connects to the backend server render(){ } }
现在,我们需要处理当组件安装在浏览器上时发生的事情。 我们希望应用程序连接到后端服务器并在组件挂载时获取消息,因此我们将使用 componentDidMount(). 您可以通过在 render()功能:
... componentDidMount() { this.client.onopen = () => { console.log("WebSocket Client Connected"); }; this.client.onmessage = (message) => { const dataFromServer = JSON.parse(message.data); if (dataFromServer) { this.setState((state) => ({ messages: [ ...state.messages, { msg: dataFromServer.text, name: dataFromServer.sender, }, ], })); } }; } render() { ...
接下来,我们将创建用于更新状态的表单。 我们将创建一个表单来更新 name发件人和房间名称。 然后,我们将创建另一个处理表单提交的表单。 将下面的代码粘贴到 render()功能:
不要错过 The Replay 来自 LogRocket 的精选时事通讯
了解 LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题
使用 React 的 useEffect 优化应用程序的性能
之间切换 在多个 Node 版本
了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画
探索 Tauri ,一个用于构建二进制文件的新框架
比较 NestJS 与 Express.js
render() { const { classes } = this.props; return ({this.state.filledForm ? ( ); } export default withStyles(useStyles)(App);Room Name: {this.state.room}) : ({this.state.messages.map((message) => ( <> > ))} )}
当您填写房间名称和寄件人姓名时, filledForm将改为 true在该状态下,将呈现输入消息的表单。 在我们的代码中,我们使用了一些需要导入的 MUI 类。 您可以通过将以下代码粘贴到您的顶部 App.js文件:
import Button from "@material-ui/core/Button"; import CssBaseline from "@material-ui/core/CssBaseline"; import TextField from "@material-ui/core/TextField"; import Container from "@material-ui/core/Container"; import Card from "@material-ui/core/Card"; import CardHeader from "@material-ui/core/CardHeader"; import Paper from "@material-ui/core/Paper"; import { withStyles } from "@material-ui/core/styles"; const useStyles = (theme) => ({ submit: { margin: theme.spacing(3, 0, 2), }, });
提交消息表单后,我们将在单击提交按钮时将文本发送到后端服务器。 将下面的代码直接粘贴到上面 componentDidMount()功能:
onButtonClicked = (e) => { this.client.send( JSON.stringify({ type: "message", text: this.state.value, sender: this.state.name, }) ); this.state.value = ""; e.preventDefault(); }; componentDidMount() { ...
现在我们已经完成了应用程序的编码,我们可以对其进行测试。 首先,通过运行以下命令启动后端服务器。 确保您位于 manage.py文件是:
python manage.py runserver
在另一个终端窗口中,导航到 frontend/目录并通过运行以下命令来运行前端服务器。 React 应用程序将自动打开:
npm start
填写姓名和房间名称。 然后,在另一个名称不同但房间名称相同的浏览器中打开应用程序。 现在,您可以开始与自己聊天,您会注意到消息是实时收到的:
在本文中,我们了解了 WebSockets、它的应用程序以及如何通过利用 Django Channels 在 Django 中使用它。 最后,我们介绍了如何使用 React 建立与 Django 服务器的 WebSocket 连接。
尽管我们构建了一个高效的实时聊天应用程序,但您仍然可以进行改进。 例如,要存储消息,您可能会包含一个数据库连接。 作为本地后端的替代方案,您可以考虑使用 Redis 作为消息代理。
我希望您喜欢这篇文章,如果您有任何问题,请务必发表评论。 快乐编码!
调试 React 应用程序可能很困难,尤其是当用户遇到难以重现的问题时。 如果您对监控和跟踪 Redux 状态、自动显示 JavaScript 错误以及跟踪缓慢的网络请求和组件加载时间感兴趣,请 尝试 LogRocket 。
LogRocket 就像一个用于 Web 和移动应用程序的 DVR,几乎可以记录您的 React 应用程序上发生的所有事情。 无需猜测问题发生的原因,您可以汇总并报告问题发生时应用程序所处的状态。 LogRocket 还监控您的应用程序的性能,并使用客户端 CPU 负载、客户端内存使用情况等指标进行报告。
LogRocket Redux 中间件包为您的用户会话增加了一层额外的可见性。 LogRocket 记录来自 Redux 存储的所有操作和状态。