详解Django3中直接添加Websockets方式


Posted in Python onFebruary 12, 2020

现在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使用正则搜索字符串或文件中的浮点数代码实例
Jul 11 Python
python判断图片宽度和高度后删除图片的方法
May 22 Python
Scrapy抓取京东商品、豆瓣电影及代码分享
Nov 23 Python
Python全排列操作实例分析
Jul 24 Python
Python wxPython库Core组件BoxSizer用法示例
Sep 03 Python
Django之使用内置函数和celery发邮件的方法示例
Sep 16 Python
python tornado使用流生成图片的例子
Nov 18 Python
Python面向对象之多态原理与用法案例分析
Dec 30 Python
python之生成多层json结构的实现
Feb 27 Python
python GUI库图形界面开发之PyQt5布局控件QVBoxLayout详细使用方法与实例
Mar 06 Python
Python抓包并解析json爬虫的完整实例代码
Nov 03 Python
Python数据分析库pandas高级接口dt的使用详解
Dec 11 Python
Tensorflow 使用pb文件保存(恢复)模型计算图和参数实例详解
Feb 11 #Python
TensorFlow:将ckpt文件固化成pb文件教程
Feb 11 #Python
TensorFlow获取加载模型中的全部张量名称代码
Feb 11 #Python
tensorflow 获取checkpoint中的变量列表实例
Feb 11 #Python
python使用正则表达式去除中文文本多余空格,保留英文之间空格方法详解
Feb 11 #Python
python 函数中的参数类型
Feb 11 #Python
python正则过滤字母、中文、数字及特殊字符方法详解
Feb 11 #Python
You might like
全国FM电台频率大全 - 8 黑龙江省
2020/03/11 无线电
PHP验证终端类型是否为手机的简单实例
2017/02/07 PHP
PHP 实现页面静态化的几种方法
2017/07/23 PHP
thinkPHP3.2.3实现阿里大于短信验证的方法
2018/06/06 PHP
文本框根据输入内容自适应高度的代码
2011/10/24 Javascript
Jquery中使用setInterval和setTimeout的方法
2013/04/08 Javascript
JavaScript学习笔记之JS事件对象
2015/01/22 Javascript
javascript计时器详解
2015/02/28 Javascript
JavaScript定义数组的三种方法(new Array(),new Array('x','y')
2016/10/04 Javascript
Vue.js系列之项目搭建(1)
2017/01/03 Javascript
Bootstrap modal 多弹窗之叠加显示不出弹窗问题的解决方案
2017/02/23 Javascript
解决vue的变量在settimeout内部效果失效的问题
2018/08/30 Javascript
详解JavaScript的变量
2019/04/04 Javascript
vue中的使用token的方法示例
2020/03/10 Javascript
JS继承实现方法及优缺点详解
2020/09/02 Javascript
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
[54:25]Ti4 循环赛第三日LGD vs MOUZ
2014/07/12 DOTA
Python类属性与实例属性用法分析
2015/05/09 Python
Python按行读取文件的简单实现方法
2016/06/22 Python
python编程线性回归代码示例
2017/12/07 Python
python微信跳一跳游戏辅助代码解析
2018/01/29 Python
Python命令行解析模块详解
2018/02/01 Python
python生成n个元素的全组合方法
2018/11/13 Python
django模板结构优化的方法
2019/02/28 Python
Python 创建守护进程的示例
2020/09/29 Python
新西兰领先的内衣店:Bendon Lingerie新西兰
2018/07/11 全球购物
巴西Mr. Cat在线商店:购买包包和鞋子
2019/09/08 全球购物
什么是java序列化,如何实现java序列化
2012/11/14 面试题
中学生校园广播稿
2014/01/16 职场文书
门前三包责任书
2014/04/15 职场文书
大学生活动总结模板
2014/07/02 职场文书
网站出售协议书范文
2014/10/10 职场文书
党员干部反四风民主生活会对照检查材料思想汇报
2014/10/12 职场文书
矛盾论读书笔记
2015/06/29 职场文书
使用vue-element-admin框架从后端动态获取菜单功能的实现
2021/04/29 Vue.js
css清除浮动clearfix:after的用法详解(附完整代码)
2023/05/21 HTML / CSS