vue如何和django后端做websocket通信
Django-Channels使用
0.本文基于Django2.1,channels2.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