Django-Channels使用
0.本文基于Django==2.1,channels==2.1.3,channels-redis==2.3.0。
1.在 settings.py 加入和 channels 相关的基础设置:
在INSTALLED_APPS加入 'channels',
# 指定ASGI的路由地址ASGI_APPLICATION = "RestaurantOrder.routing.application"
#配置websocket通道层的后端数据库依赖
#指定redis [channel layer是一种通信系统,允许多个consumer实例之间互相通信,以及与外部Djanbo程序实现互通]
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
2.编写路由文件项目settings同级目录/routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
3.子应用目录下添加routing.py文件
from django.urls import path
from chat.consumers import ChatConsumer
websocket_urlpatterns = [
path('ws/chat/', ChatConsumer),
]
4.编写子应用下的consumer.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer #异步,实现更好的性能
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
# connect方法在连接建立时触发
self.room_group_name = 'chat_test'
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# disconnect在连接关闭时触发
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
# receive方法会在收到消息后触发
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = '测试聊天室:' + event['message']
# Send message to WebSocket 【最后在这里发送返回前端页面】
await self.send(text_data=json.dumps({
'message': message
}))
至此,django后端已经具备websocket连接功能
5.前端VUE如何连接后端websocket?
5.1本地localhost需要在vue.config.js配置代理
'/ws':{
// target: ``,
timeout: 60000,
// target: '', // 测试服
changeOrigin: true,
ws: true,
pathRewrite: {
'^/ws': '/ws'
// 重写,
}
}
5.2线上环境需要配置nginx代理
location /ws {
proxy_pass https://abc.com/ws;
proxy_connect_timeout 4s;
proxy_read_timeout 360s;
proxy_send_timeout 12s;
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket"; # 重要
proxy_set_header Connection "Upgrade"; # 重要
}
5.3代码里
initWebSocket() {
//初始化websocket
// var wsuri = "ws://127.0.0.1:8080";
var ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
var ws_on_line =ws_scheme + '://' + window.location.host + '/ws/chat/'
// 本地走代理/vue.config.js,线上也代理nginx代理
var weburl = GLOBAL.httpWsUrl + "ws/chat";
// var ws_scheme = window.location.protocol==="https:"?"wss":"ws"
this.websock = new WebSocket(ws_on_line);
this.websock.onopen = this.websocketonopen;
this.websock.onmessage = this.websocketonmessage;
this.websock.onerror = this.websocketonerror;
// this.websock.onclose = this.websocketclose;
},
websocketonopen() {
//连接建立之后执行send方法发送数据
console.log("建立连接");
var actions = { message: "连接测试" }; this.websocketsend(JSON.stringify(actions));
},
websocketonerror(e) {
//连接建立失败重连
console.log("连接error", e);
this.initWebSocket();
},
websocketonmessage(e) {
//数据接收
this.websocket_data = JSON.parse(e.data);
console.log("websocket-res",JSON.stringify(this.websocket_data))
console.log("接收后端数据type",typeof(this.websocket_data))
// 将websocket消息展示在消息提示框
var h = this.$createElement;
// 创建html元素
this.hrender = h("p", null, [
h(
"div", [
h("div",
JSON.stringify(this.websocket_data.message)),
// 传变量
// },
// }),
],
null
),
]);
if(this.websocket_data.message['result']){
const instance = this.$notify
({
title: "提示语",
message: this.hrender,
type: "success",
// duration: 0, // 配置是否自动关闭,如果为0则不会关闭
});
}
},
websocketsend(Data) {
//数据发送
this.websock.send(Data); },
websocketclose(e){ //关闭
console.log('断开连接',e); },
至此,vue和django后端websocket连接通讯建立,后端可自定义发送方法,在特定代码执行阶段发送消息给客户端
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()#
发送websocket消息
def send_ws_msg(data):
group_name = "chat_test"
async_to_sync(channel_layer.group_send)
(group_name, { 'type': 'chat_message', 'message': data })
return
let webSocket = null
let socketOpen = false
function doSend(message)
{
if (socketOpen)
{
sys_log_list.length = 0 webSocket.send(message) }
}
function contactSocket()
{ if ('WebSocket' in window)
{
const ws_scheme = window.location.protocol === 'https:' ? 'wss' : 'ws'
const ws_url = ws_scheme + '://' + window.location.host + '/ws/syslogsearch/'
webSocket = new WebSocket(ws_url)
webSocket.onopen = function()
{ console.log('连接成功!') socketOpen = true }
webSocket.onmessage = function(evt)
{ var received_msg = evt.data console.log('接受消息:',
JSON.parse(received_msg)['message'])
if (JSON.parse(received_msg)['message']['count'] === 0)
{ message.error('没有日志数据!') }
if (JSON.parse(received_msg)['message']['count'] === 1)
{ message.success('请求完成!') }
sys_log_list.push(JSON.parse(received_msg)['message'])
nextTick(() =>
{
sys_log_page.value = 1
sys_log_pageSize.value = 10
sys_log_pageCount.value = Math.ceil(sys_log_list.length / 10) }) }
webSocket.onclose = function() { console.log('连接关闭!') }
webSocket.onerror = function() { console.log('连接异常!') } }}