如何在没有额外依赖的情况下将Websockets添加到Django应用

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

入门

首先,您需要在计算机上安装Python> = 3.6。 Django 3.0仅与Python 3.6及更高版本兼容,因为它使用了asyncawait关键字。 完成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 application程序,可以使用uvicorndaphne类的ASGI服务器运行该application程序。 在进一步介绍之前,让我们看一下ASGI应用程序的结构。

ASGI应用程序结构

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

ASGI应用程序是一个async函数,它带有3个参数: scope (当前请求的上下文), receive (一个async函数,可让您监听传入的事件)和send (一个async函数,可将事件发送至客户端)。

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

创建一个ASGI应用

在我们的asgi.py文件中,我们将使用我们自己的ASGI应用程序包装Django的默认ASGI应用程序功能,以便自己处理Websocket连接。 为此,我们需要定义一个名为applicationasync函数,该函数接受3个ASGI参数: scopereceivesend 。 将get_asgi_application调用的结果重命名为django_application ,因为我们需要它处理HTTP请求。 在我们的application函数内部,我们将检查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 ,并在我们的application函数内部调用它来处理Websocket请求,并传递scopereceivesend参数。 它看起来应该像这样:

# 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!"响应"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应用程序中。 去用它来制作很棒的东西😎

👋嗨,我是杰登。 我喜欢构建应用程序,并教别人如何构建应用程序。 有关使用Django,React和GraphQL构建应用程序的更多信息,请在 Twitter上 关注我, 或通过 jaydenwindle.com 订阅我的时事通讯

From: https://hackernoon.com/how-to-add-websockets-to-a-django-app-without-extra-dependencies-u61537a2

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值