1. 程式人生 > 程式設計 >詳解Django3中直接新增Websockets方式

詳解Django3中直接新增Websockets方式

現在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,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',send):
  if scope['type'] == 'http':
    await django_application(scope,send)
  elif scope['type'] == 'websocket':
    await websocket_application(scope,send)
  else:
    raise NotImplementedError(f"Unknown scope type {scope['type']}")
 
# websocket.py
async def websocket_application(scope,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,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應用程式中。 去用它來製作很棒的東西。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。