轻松实现实时通信:如何使用 Django 创建基于 WebSockets 的自定义 API

还记得《老友记》里钱德勒和乔伊在网上打游戏,却一直被罗斯和瑞秋打断的那一集吗?如果他们有一个实时聊天应用程序就好了,他们就可以互相交谈,而不是隔着公寓大喊大叫。

在深入了解 Django 和 WebSockets 的世界之前,让我们先来看看 WebSockets 是什么以及它们是如何工作的。

WebSocket 简介

WebSockets 是一种协议,允许客户端和服务器之间通过单个长期连接进行双向通信。这与传统的 HTTP 请求-响应模式形成鲜明对比,后者涉及客户端向服务器发出请求,而服务器则以单个静态响应进行响应。

要理解 HTTP 和 WebSockets 之间的区别,我们可以用《老友记》中的一个例子来说明。在一集中,罗斯正试图把沙发搬上狭窄的楼梯,他很难把沙发搬到拐角处。他最终通过转动沙发把它搬到了拐角处,但为此他不得不上下楼梯多次。

这与 HTTP 模型类似。每次客户端(罗斯)向服务器(沙发)发出请求时,服务器都会发回一个静态响应(沙发的位置)。罗斯必须不断发出请求(上下楼),才能获得移动沙发所需的信息。

相比之下,WebSockets 就像一个站在楼梯顶端的朋友(我们称她为 Phoebe),她可以看到正在发生的一切。罗斯可以与菲比进行实时通信,菲比可以在他移动沙发时向他提供沙发位置的最新信息。这使得整个过程更加高效和有效。

轻松实现实时通信:如何使用 Django 创建基于 WebSockets 的自定义 API

Django 和 WebSockets

既然我们已经对 WebSockets 有了基本的了解,那么让我们来看看如何在 Django 中使用它们。

Django 是一个流行的网络框架,用于用 Python 构建网络应用程序。虽然 Django 没有内置的 WebSockets 支持,但有几个第三方库可以让 Django 轻松使用 WebSockets。

Channels 就是这样一个库,它为 WebSockets 提供了一层抽象层,允许客户端和服务器之间进行实时通信。Channels 建立在 ASGI(异步服务器网关接口)规范之上,旨在处理客户端和服务器之间的异步通信。

继续我们在《老友记》中的比喻,Channels 就像乔伊帮罗斯搬沙发一样。乔伊是搬运家具的专家,他知道把沙发搬上狭窄楼梯的所有最佳技巧。有了乔伊的帮助,罗斯就能更高效、更有效地搬动沙发了。

使用 Django 和 WebSockets 创建聊天应用程序

现在我们了解了 Django 和 WebSockets 的基础知识,让我们使用 Django 和 Channels 创建一个简单的聊天应用程序。

在我们的聊天应用程序中,用户可以加入聊天室,并向同一聊天室中的其他用户实时发送消息。

设置我们的项目

开始之前,我们需要创建一个新的 Django 项目并安装 Channels:

$ django-admin startproject websocket_demo
$ cd websocket_demo
$ python -m venv venv
$ source venv/bin/activate
$ pip install channels

创建 WebSocket 消费者

接下来,我们将在项目根目录下创建一个名为 consumers.py 的新文件。该文件将包含 WebSocket 消费者的代码,它将处理传入的 WebSocket 连接和消息。

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        await self.send(text_data=json.dumps({
            'message': message
        }))

让我们分解一下这段代码的作用:

  • 从 Channels 库导入AsyncWebsocketConsumer类。
  • 创建一个名为 ChatConsumer 的新类,它继承自AsyncWebsocketConsumer.
  • 定义了三个方法:connectdisconnectreceive。这些方法分别处理 WebSocket 连接、断开连接和传入消息。
  • connect方法中,我们接受 WebSocket 连接。
  • disconnect方法中,(暂时)什么都不做。
  • receive方法中,我们将传入消息解析为 JSON,提取消息文本,然后将消息发送回客户端。

路由 WebSocket 请求

接下来,我们需要为 WebSocket 消费者定义一个 URL 路由。我们将在项目的根目录中创建一个名为routing.py的新文件:

from django.urls import re_path

from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/$', consumers.ChatConsumer.as_asgi()),
]

该文件定义了向 /ws/chat/ 发送 WebSocket 请求的 URL 路由。当向该 URL 发出 WebSocket 请求时,将由 ChatConsumer 处理。

更新 Django 设置

最后,我们需要更新 Django 设置以包含 Channels:

INSTALLED_APPS = [
    # ...
    'channels',
]

ASGI_APPLICATION = 'websocket_demo.routing.application'

我们添加'channels'到  INSTALLED_APPS,并指定ASGI_APPLICATIONas websocket_demo.routing.application

测试我们的应用程序

现在我们的应用程序已经设置完毕,让我们测试一下!首先,我们将启动 Django 开发服务器:

$ python manage.py runserver

接下来,打开浏览器并导航到http://localhost:8000/ws/chat/. 启动ChatConsumer.

我们现在可以打开浏览器控制台并执行以下 JavaScript 代码以向服务器发送消息:

const chatSocket = new WebSocket('ws://localhost:8000/ws/chat/');

chatSocket.onopen = function() {
  console.log('WebSocket connection established.');
  const message = {
    'message': 'Hello, world!'
  };
  chatSocket.send(JSON.stringify(message));
};

chatSocket.onmessage = function(event) {
  const message = JSON.parse(event.data);
  console.log('Received message:', message);
};

当我们执行这段代码时,我们应该看到一条消息打印到控制台,上面写着“Received message: { message: ‘Hello, world!’” }”。这证实了我们的 WebSocket 连接正在工作,并且我们能够实时发送和接收消息!

Channels的高级功能

Channels 是一个功能强大的库,它为使用 WebSockets 构建实时应用程序提供了许多高级功能。在本节中,我们将探讨 Channels 的一些最有用的功能以及如何在 Django 中使用它们。

群组通信

Channels 最有用的功能之一是将 WebSocket 连接分组在一起的能力。这允许您一次向多个客户端发送消息,而不是单独向每个客​​户端发送消息。

要在频道中使用群组通信,您首先需要导入ChannelLayer对象:

from channels.layers import get_channel_layer
channel_layer = get_channel_layer()

获得ChannelLayer对象后,您可以使用group_addgroup_discard、 和group_send方法来管理组并向组成员发送消息。以下是如何使用这些方法的示例:

async def connect(self):
    self.room_name = self.scope['url_route']['kwargs']['room_name']
    self.room_group_name = 'chat_%s' % self.room_name

    await self.channel_layer.group_add(
        self.room_group_name,
        self.channel_name
    )

    await self.accept()

async def disconnect(self, close_code):
    await self.channel_layer.group_discard(
        self.room_group_name,
        self.channel_name
    )

async def receive(self, text_data):
    text_data_json = json.loads(text_data)
    message = text_data_json['message']

    await self.channel_layer.group_send(
        self.room_group_name,
        {
            'type': 'chat_message',
            'message': message
        }
    )

async def chat_message(self, event):
    message = event['message']

    await self.send(text_data=json.dumps({
        'message': message
    }))

在此示例中,我们使用群组通信来创建一个聊天室,多个客户端可以在其中互相发送消息。当客户端连接到 WebSocket 时,我们将他们的频道添加到与他们加入的聊天室相对应的组中。当客户端发送消息时,我们使用group_send方法将消息发送给聊天室中的所有客户端。最后,我们定义一个chat_message方法,当组成员收到消息时调用该方法,该方法将消息发送回客户端。

处理二进制数据

默认情况下,Channels 只处理 WebSocket 消息中的文本数据。不过,你也可以使用 bytes 类型而不是 str 来发送二进制数据,如图像或音频。

要发送二进制数据,您需要使用bytes方法而不是json.dumps序列化数据。以下是如何发送二进制图像的示例:

import base64

async def receive(self, text_data):
    bytes_data = base64.b64decode(text_data)
    # handle binary data here

在此示例中,我们将 Base64 编码的字符串解码为二进制数据,然后我们可以根据需要进行处理。

后台任务

有时,需要执行长时间运行或异步任务以响应 WebSocket 消息。例如,可能需要处理大型数据集、发送电子邮件或发出 API 请求。

Channels 提供了一种使用 async_too_sync SyncConsumer 运行后台任务的方法。下面是一个如何运行后台任务以响应 WebSocket 消息的示例:

from asgiref.sync import async_to_sync
from channels.generic.sync import SyncConsumer

class TaskConsumer(SyncConsumer):
    def task(self, message):
        # long-running or asynchronous task

        return 'Task complete!'

async def receive(self, text_data):
    message = json.loads(text_data)
    task_type = message['task_type']
    task_args = message['task_args']

    response = await async_to_sync(TaskConsumer().task)(task_args)

    await self.send(text_data=json.dumps({
        'response': response
    }))

在本例中,我们定义了一个任务消费者(TaskConsumer),当任务方法被调用时,它将运行一个长期运行的异步任务。然后,我们使用 async_to_sync 在后台线程中运行任务方法。

在 receive 方法中,我们将解析一条包含要运行任务的类型和参数的消息。然后,我们使用 async_to_sync 调用带有指定参数的 TaskConsumer,并返回结果。最后,我们使用 WebSocket 连接将结果发送回客户端。

结论

在本文中,我们探索了 WebSockets 的世界,以及如何在 Django 中使用 WebSockets 在客户端和服务器之间创建实时通信。我们用 Friends 电视剧作为有趣的类比来解释 WebSockets 和通道的基础知识,并创建了一个简单的聊天应用程序来演示如何在 Django 中使用 WebSockets。

有了 WebSockets 和 Django,应用程序中的实时通信和交互就有了无限可能。无论您是要构建一个聊天应用程序、一个协作编辑平台还是一个实时仪表盘,WebSockets 都能提供一种强大而高效的方式来处理客户端和服务器之间的实时数据传输。

希望这篇文章能为您在 Django 中开始使用 WebSockets 提供信息和帮助。如需进一步阅读,建议查看官方 Channels 文档和 Django 异步视图文档。如果您是《老友记》的粉丝,我们建议您回去重看一些经典剧集,看看实时通信是如何在罗斯、瑞秋、钱德勒、莫妮卡、乔伊和菲比的生活中发挥作用的!

本文为原创稿件,版权归作者所有,如需转载,请注明出处:https://www.nxrte.com/jishu/im/30155.html

(0)

相关推荐

发表回复

登录后才能评论