详解Django3中直接添加Websockets方式

所属分类: 脚本专栏 / python 阅读数: 1624
收藏 0 赞 0 分享

现在Django 3.0附带了对ASGI的支持,将Websockets添加到Django应用中不需要任何额外的依赖关系。 在本文中,您将学习如何通过扩展默认的ASGI应用程序来使用Django处理Websocket。 我们将介绍如何在示例ASGI应用程序中处理Websocket连接,发送和接收数据以及实现业务逻辑。

入门

首先,您需要在计算机上安装Python> = 3.6。 Django 3.0仅与Python 3.6及更高版本兼容,因为它使用了async和await关键字。 完成Python版本设置后,创建一个项目目录并CD进入。 然后,将Django安装在virtualenv内,并在您的项目目录中创建一个新的Django应用:

$ mkdir django_websockets && cd django_websockets
$ python -m venv venv
$ source venv/bin/activate
$ pip install django
$ django-admin startproject websocket_app .

看一下Django应用程序的websocket_app目录。 您应该看到一个名为asgi.py的文件。 其内容如下所示:

import os
 
from django.core.asgi import get_asgi_application
 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')
 
application = get_asgi_application()

该文件提供了默认的Django ASGI设置,并公开了一个名为application的ASGI应用程序,可以使用uvicorn或daphne等ASGI服务器运行该应用程序。 在进一步介绍之前,让我们看一下ASGI应用程序的结构。

ASGI应用程序结构

ASGI或“异步服务器网关接口”是用于使用Python构建异步Web服务的规范。它是WSGI的精神继承者,WSGI已被Django和Flask等框架使用了很长时间。 ASGI使您可以使用Python的本机异步/等待功能来构建支持长期连接的Web服务,例如Websockets和Server Sent Events。

ASGI应用程序是一个异步函数,它带有3个参数:作用域(当前请求的上下文),接收(一个异步函数,可让您侦听传入的事件)和发送(一个异步函数,可将事件发送至客户端)。

在ASGI应用程序内部,您可以根据范围字典中的值路由请求。例如,您可以通过检查scope [‘type']的值来检查该请求是HTTP请求还是Websocket请求。要侦听来自客户端的数据,您可以等待接收功能。准备好将数据发送到客户端时,可以等待发送功能,然后将要发送给客户端的任何数据传递给客户端。让我们看一下这在示例应用程序中是如何工作的。

创建一个ASGI应用

在我们的asgi.py文件中,我们将使用我们自己的ASGI应用程序包装Django的默认ASGI应用程序功能,以便自己处理Websocket连接。为此,我们需要定义一个名为application的异步函数,该函数需要3个ASGI参数:scope,receive和send。将get_asgi_application调用的结果重命名为django_application,因为我们需要它处理HTTP请求。在我们的应用程序函数内部,我们将检查scope [‘type']的值以确定请求类型。如果请求类型为“ http”,则该请求为普通的HTTP请求,我们应该让Django处理它。如果请求类型为“ websocket”,那么我们将自己处理逻辑。生成的asgi.py文件应如下所示:

import os
 
from django.core.asgi import get_asgi_application
 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')
 
django_application = get_asgi_application()
 
async def application(scope, receive, send):
  if scope['type'] == 'http':
    # Let Django handle HTTP requests
    await django_application(scope, receive, send)
  elif scope['type'] == 'websocket':
    # We'll handle Websocket connections here
    pass
  else:
    raise NotImplementedError(f"Unknown scope type {scope['type']}")

现在,我们需要创建一个函数来处理Websocket连接。 在与asgi.py文件相同的文件夹中创建一个名为websocket.py的文件,并定义一个名为websocket_application的ASGI应用程序函数,该函数接受3个ASGI参数。 接下来,我们将在我们的asgi.py文件中导入websocket_application,并在我们的应用程序函数内部调用它来处理Websocket请求,传入范围,接收和发送参数。 它看起来应该像这样:

# asgi.py
import os
 
from django.core.asgi import get_asgi_application
from websocket_app.websocket import websocket_application
 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')
 
django_application = get_asgi_application()
 
async def application(scope, receive, send):
  if scope['type'] == 'http':
    await django_application(scope, receive, send)
  elif scope['type'] == 'websocket':
    await websocket_application(scope, receive, send)
  else:
    raise NotImplementedError(f"Unknown scope type {scope['type']}")
 
# websocket.py
async def websocket_application(scope, receive, send):
  pass

接下来,让我们为Websocket应用程序实现一些逻辑。我们将监听所有Websocket连接,当客户端发送字符串“ ping”时,我们将以字符串“ pong!”进行响应。

在websocket_application函数内部,我们将定义一个不确定的循环,该循环将处理Websocket请求,直到关闭连接。在该循环内,我们将等待服务器从客户端收到的任何新事件。然后,我们将根据事件的内容采取行动,并将响应发送给客户端。

首先,让我们处理连接。当新的Websocket客户端连接到服务器时,我们将收到“ websocket.connect”事件。为了允许这种连接,我们将发送一个“ websocket.accept”事件作为响应。这将完成Websocket握手并与客户端建立持久连接。

当客户端终止其与服务器的连接时,我们还需要处理断开连接事件。为此,我们将监听“ websocket.disconnect”事件。当客户端断开连接时,我们将摆脱不确定的循环。

最后,我们需要处理来自客户端的请求。为此,我们将监听“ websocket.receive”事件。当我们从客户端收到“ websocket.receive”事件时,我们将检查event [‘text']的值是否为“ ping”。如果是,我们将发送一个'websocket.send'事件,其文本值为'pong!'。

设置Websocket逻辑后,我们的websocket.py文件应如下所示:

# websocket.py
async def websocket_application(scope, receive, send):
  while True:
    event = await receive()
 
    if event['type'] == 'websocket.connect':
      await send({
        'type': 'websocket.accept'
      })
    
    if event['type'] == 'websocket.disconnect':
      break
    
    if event['type'] == 'websocket.receive':
      if event['text'] == 'ping':
        await send({
          'type': 'websocket.send',
          'text': 'pong!'
        })

测试

现在,我们的ASGI应用程序已设置为处理Websocket连接,并且我们已经实现了Websocket服务器逻辑,让我们对其进行测试。 目前,Django开发服务器不使用asgi.py文件,因此您将无法使用./manage.py runserver测试连接。 相反,您需要使用ASGI服务器(例如uvicorn)运行该应用程序。 让我们安装它:

$ pip install uvicorn

安装uvicorn后,我们可以使用以下命令运行ASGI应用程序:

$ uvicorn websocket_app.asgi:application
INFO:   Started server process [25557]
INFO:   Waiting for application startup.
INFO:   ASGI 'lifespan' protocol appears unsupported.
INFO:   Application startup complete.
INFO:   Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

要测试Websocket连接,请在新选项卡中打开浏览器的开发工具。 在控制台中,创建一个名为ws的新Websocket实例,该实例指向ws:// localhost:8000 /。 然后将onmessage处理程序附加到将event.data记录到控制台的ws。 最后,调用ws.send('ping')将消息发送到服务器。 您应该看到值“ pong!”。 登录到控制台。

> ws = new WebSocket('ws://localhost:8000/')
 WebSocket {url: "ws://localhost:8000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
> ws.onmessage = event => console.log(event.data)
 event => console.log(event.data)
> ws.send("ping")
 undefined
 pong!

恭喜! 现在,您知道了如何使用ASGI将Websocket支持添加到Django应用程序中。 去用它来制作很棒的东西。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

Python实现按学生年龄排序的实际问题详解

这篇文章主要给大家介绍了关于Python实现按学生年龄排序实际问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
收藏 0 赞 0 分享

Python开发的HTTP库requests详解

Requests是用Python语言编写,基于urllib,采用Apache2 Licensed开源协议的HTTP库。它比urllib更加方便,可以节约我们大量的工作,完全满足HTTP测试需求。Requests的哲学是以PEP 20 的习语为中心开发的,所以它比urllib更加P
收藏 0 赞 0 分享

Python网络爬虫与信息提取(实例讲解)

下面小编就为大家带来一篇Python网络爬虫与信息提取(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

在python3环境下的Django中使用MySQL数据库的实例

下面小编就为大家带来一篇在python3环境下的Django中使用MySQL数据库的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Python 3.x读写csv文件中数字的方法示例

在我们日常开发中经常需要对csv文件进行读写,下面这篇文章主要给大家介绍了关于Python 3.x读写csv文件中数字的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
收藏 0 赞 0 分享

Python实现解析Bit Torrent种子文件内容的方法

这篇文章主要介绍了Python实现解析Bit Torrent种子文件内容的方法,结合实例形式分析了Python针对Torrent文件的读取与解析相关操作技巧与注意事项,需要的朋友可以参考下
收藏 0 赞 0 分享

Python实现文件内容批量追加的方法示例

这篇文章主要介绍了Python实现文件内容批量追加的方法,结合实例形式分析了Python文件的读写相关操作技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

Python简单实现自动删除目录下空文件夹的方法

这篇文章主要介绍了Python简单实现自动删除目录下空文件夹的方法,涉及Python针对文件与目录的读取、判断、删除等相关操作技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

简单学习Python多进程Multiprocessing

这篇文章主要和大家一起简单的学习Python多进程Multiprocessing ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Python导入模块时遇到的错误分析

这篇文章主要给大家详细解释了在Python处理导入模块的时候出现错误以及具体的情况分析,非常的详尽,有需要的小伙伴可以参考下
收藏 0 赞 0 分享
查看更多