django使用websocket並實現簡易聊天室
django默認只支持http協議
如果你想讓django即支持http協議又支持websocket協議,則需要做以下配置
前期配置
前提需要安裝channels:
channles的安裝:
"""
注意事項
1.不要安裝最新版本的channles,建議安裝2.3版本即可
2.python解釋器建議使用3.6
"""
pip3 install channels==2.3
1.配置文件中注冊channels應用
INSTALLED_APPS = [
# 1 注冊channles應用
'channels'
]
2.settings.py配置文件配置參數
# 2 配置啟動需要的參數
ASGI_APPLICATION = 'myapi.routing.application'
# ASGI_APPLICATION = '項目名同名的文件夾名.內部的py文件名(默認就叫routing).routing文件內的變量名(默認就叫application)'
3.固定配置
# 在項目名同名的文件夾下創建routing.py文件並在該文件內提前寫好以下代碼
from channels.routing import ProtocolTypeRouter,URLRouter
from django.conf.urls import url
from app01 import consumers
application =ProtocolTypeRouter({
'websocket':URLRouter([
# websocket請求路由與視圖函數的對應關系
url(r'^chat/$',consumers.ChatConsumer)
])
})
總結:配置完成后django由原來默認的wsgiref替換成asgi啟動(asgi內部是基於達芙妮)
上述配置完成后 ,django就會同時支持http協議和websocket協議
"""
原先基於http協議的路由與視圖函數對應關系還是跟之前一樣urls.py、views.py
針對websocket協議的路由與視圖函數對應關系則需要在routing.py和consumers.py(在對應的應用下創建即可)
"""
業務邏輯代碼
# consumers.py
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""
客戶端請求鏈接之后自動觸發
:param message: 消息數據
"""
pass
def websocket_receive(self, message):
"""
客戶端瀏覽器發送消息來的時候自動觸發
:param message: 消息數據
"""
pass
def websocket_disconnect(self, message):
"""
客戶端斷開鏈接之后自動觸發
:param message:
"""
pass
基於channels完成聊天室
"""
http協議
index >>> index函數
訪問:瀏覽器發送請求即可
websocket協議
chat >>> ChatConsumer類(3個方法)
訪問:借助於new WebSocket對象
"""
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
consumer_object_list = []
class ChatConsumer(WebsocketConsumer):
def websocket_connect(self, message):
"""
客戶端請求鏈接之后自動觸發
:param message: 消息數據
"""
# print('請求鏈接')
self.accept() # 建立鏈接
# 鏈接成功之后就將當前鏈接對象往列表中存一份
consumer_object_list.append(self)
def websocket_receive(self, message):
"""
客戶端瀏覽器發送消息來的時候自動觸發
:param message: 消息數據 {'type': 'websocket.receive', 'text': '你好啊 美女'}
"""
# print(message)
text = message.get('text')
# 給客戶端回復消息
# self.send(text_data=text)
# 我們要給所有的鏈接對象回復消息
# 實現群發的簡易版本
for obj in consumer_object_list:
obj.send(text_data=text)
def websocket_disconnect(self, message):
"""
客戶端斷開鏈接之后自動觸發
:param message:
"""
# 客戶端斷開鏈接之后 應該將當前客戶端對象從列表中移除
consumer_object_list.remove(self)
raise StopConsumer() # 主動報異常 無需做處理 內部自動捕獲
<h1>聊天室</h1>
<div>
<input type="text" id="text" placeholder="請輸入">
<input type="button" value="發送" onclick="sendMsg()">
<input type="button" value="斷開鏈接" onclick="close()">
</div>
<h1>聊天紀錄</h1>
<div id="content">
</div>
<script>
var ws = new WebSocket('ws://127.0.0.1:8000/chat/');
// 1 發送消息 ws.send()
// 2 握手成功之后 自動觸發 ws.onopen
// 3 服務端發送消息過來 自動觸發 ws.onmessage
// 4 斷開鏈接 ws.close()
// 0 握手成功之后自動觸發
ws.onopen = function () {
alert('建立成功')
};
// 1 給服務端發送消息
function sendMsg() {
ws.send($('#text').val());
}
// 2 接受服務端發送過來的消息
ws.onmessage = function (event) { // event是對象
var dataValue = event.data; // 獲取服務端的數據
// 用DOM操作將數據動態渲染到頁面上
var pEle = $('<p>');
pEle.text(dataValue);
$('#content').append(pEle)
};
// 3 斷開鏈接
function close() {
ws.close()
}
</script>
總結
"""
后端三個方法
websocket_connect
websocket_receive
websocket_disconnect
前端四個方法
// 1 發送消息 ws.send()
// 2 握手成功之后 自動觸發 ws.onopen
// 3 服務端發送消息過來 自動觸發 ws.onmessage
// 4 斷開鏈接 ws.close()
"""
注意我們上面的代碼實現的群聊功能並不是真正的合理,后續如果想要真正實現群聊功能,官方提供了一個方法channel-layers模塊,
