vue如何和django后端做websocket通信

3,065 阅读2分钟

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('连接异常!')    }  }}