詳解Django3中直接添加Websockets方式
現(xiàn)在Django 3.0附帶了對ASGI的支持,將Websockets添加到Django應用中不需要任何額外的依賴關系。 在本文中,您將學習如何通過擴展默認的ASGI應用程序來使用Django處理Websocket。 我們將介紹如何在示例ASGI應用程序中處理Websocket連接,發(fā)送和接收數(shù)據(jù)以及實現(xiàn)業(yè)務邏輯。
入門
首先,您需要在計算機上安裝Python> = 3.6。 Django 3.0僅與Python 3.6及更高版本兼容,因為它使用了async和await關鍵字。 完成Python版本設置后,創(chuàng)建一個項目目錄并CD進入。 然后,將Django安裝在virtualenv內,并在您的項目目錄中創(chuàng)建一個新的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服務的規(guī)范。它是WSGI的精神繼承者,WSGI已被Django和Flask等框架使用了很長時間。 ASGI使您可以使用Python的本機異步/等待功能來構建支持長期連接的Web服務,例如Websockets和Server Sent Events。
ASGI應用程序是一個異步函數(shù),它帶有3個參數(shù):作用域(當前請求的上下文),接收(一個異步函數(shù),可讓您偵聽傳入的事件)和發(fā)送(一個異步函數(shù),可將事件發(fā)送至客戶端)。
在ASGI應用程序內部,您可以根據(jù)范圍字典中的值路由請求。例如,您可以通過檢查scope [‘type']的值來檢查該請求是HTTP請求還是Websocket請求。要偵聽來自客戶端的數(shù)據(jù),您可以等待接收功能。準備好將數(shù)據(jù)發(fā)送到客戶端時,可以等待發(fā)送功能,然后將要發(fā)送給客戶端的任何數(shù)據(jù)傳遞給客戶端。讓我們看一下這在示例應用程序中是如何工作的。
創(chuàng)建一個ASGI應用
在我們的asgi.py文件中,我們將使用我們自己的ASGI應用程序包裝Django的默認ASGI應用程序功能,以便自己處理Websocket連接。為此,我們需要定義一個名為application的異步函數(shù),該函數(shù)需要3個ASGI參數(shù):scope,receive和send。將get_asgi_application調用的結果重命名為django_application,因為我們需要它處理HTTP請求。在我們的應用程序函數(shù)內部,我們將檢查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']}")
現(xiàn)在,我們需要創(chuàng)建一個函數(shù)來處理Websocket連接。 在與asgi.py文件相同的文件夾中創(chuàng)建一個名為websocket.py的文件,并定義一個名為websocket_application的ASGI應用程序函數(shù),該函數(shù)接受3個ASGI參數(shù)。 接下來,我們將在我們的asgi.py文件中導入websocket_application,并在我們的應用程序函數(shù)內部調用它來處理Websocket請求,傳入范圍,接收和發(fā)送參數(shù)。 它看起來應該像這樣:
# 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
接下來,讓我們?yōu)閃ebsocket應用程序實現(xiàn)一些邏輯。我們將監(jiān)聽所有Websocket連接,當客戶端發(fā)送字符串“ ping”時,我們將以字符串“ pong!”進行響應。
在websocket_application函數(shù)內部,我們將定義一個不確定的循環(huán),該循環(huán)將處理Websocket請求,直到關閉連接。在該循環(huán)內,我們將等待服務器從客戶端收到的任何新事件。然后,我們將根據(jù)事件的內容采取行動,并將響應發(fā)送給客戶端。
首先,讓我們處理連接。當新的Websocket客戶端連接到服務器時,我們將收到“ websocket.connect”事件。為了允許這種連接,我們將發(fā)送一個“ websocket.accept”事件作為響應。這將完成Websocket握手并與客戶端建立持久連接。
當客戶端終止其與服務器的連接時,我們還需要處理斷開連接事件。為此,我們將監(jiān)聽“ websocket.disconnect”事件。當客戶端斷開連接時,我們將擺脫不確定的循環(huán)。
最后,我們需要處理來自客戶端的請求。為此,我們將監(jiān)聽“ websocket.receive”事件。當我們從客戶端收到“ websocket.receive”事件時,我們將檢查event [‘text']的值是否為“ ping”。如果是,我們將發(fā)送一個'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!' })
測試
現(xiàn)在,我們的ASGI應用程序已設置為處理Websocket連接,并且我們已經實現(xiàn)了Websocket服務器邏輯,讓我們對其進行測試。 目前,Django開發(fā)服務器不使用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連接,請在新選項卡中打開瀏覽器的開發(fā)工具。 在控制臺中,創(chuàng)建一個名為ws的新Websocket實例,該實例指向ws:// localhost:8000 /。 然后將onmessage處理程序附加到將event.data記錄到控制臺的ws。 最后,調用ws.send('ping')將消息發(fā)送到服務器。 您應該看到值“ 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!
恭喜! 現(xiàn)在,您知道了如何使用ASGI將Websocket支持添加到Django應用程序中。 去用它來制作很棒的東西。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
python圖形用戶界面tkinter之按鈕Button的使用說明
這篇文章主要介紹了python圖形用戶界面tkinter之按鈕Button的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06python中的os.mkdir和os.makedirs的使用區(qū)別及如何查看某個模塊中的某些字母開頭的屬性方法
這篇文章主要介紹了python中的os.mkdir和os.makedirs的使用區(qū)別及如何查看某個模塊中的某些字母開頭的屬性方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03五個Pandas?實戰(zhàn)案例帶你分析操作數(shù)據(jù)
pandas是基于NumPy的一種工具,該工具是為了解決數(shù)據(jù)分析任務而創(chuàng)建的。Pandas納入了大量庫和一些標準的數(shù)據(jù)模型,提供了高效操作大型數(shù)據(jù)集的工具。pandas提供大量快速便捷地處理數(shù)據(jù)的函數(shù)和方法。你很快就會發(fā)現(xiàn),它是使Python強大而高效的數(shù)據(jù)分析環(huán)境的重要因素之一2022-01-01