vue+django+channles实现websocket

django项目结构

-SevenDays

    --SevenDays

    --websocket

        --auth.py

        --console.py

1、SevenDays

settings.py

REDIS_OPTIONS = {
    'HOST': '127.0.0.1',
    'PORT': 6379,
    'CHS_DB': 2,
    'PASSWORD': ''
}
# django-channels配置
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": ["redis://:{}@{}:{}/{}".format(REDIS_OPTIONS['PASSWORD'], REDIS_OPTIONS['HOST'], REDIS_OPTIONS['PORT'], REDIS_OPTIONS['CHS_DB'])],
        },
    },
}
# 配置ASGI
ASGI_APPLICATION = "SevenDays.routing.application"

asgi.py

#-*-coding:utf-8-*-
import os
import django
from channels.routing import get_default_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "SevenDays.settings")
django.setup()
application = get_default_application()

routing.py

#-*-coding:utf-8-*-
from websocket.auth import TokenAuthMiddleware
from channels.routing import URLRouter, ProtocolTypeRouter
from django.conf.urls import url
from websocket.console import ConsoleMsgConsumer



application = ProtocolTypeRouter({
    "websocket": TokenAuthMiddleware(
        URLRouter([
            url(r"^websocket/console", ConsoleMsgConsumer),# 指定了websocket请求的url
        ])
    )
})

 

2、websocket

auth.py

#-*-coding:utf-8-*-
from channels.auth import AuthMiddlewareStack
from django.conf import LazySettings
from urllib import parse
from users.models.user import u_account
from django.db import close_old_connections
from utils.public_method import get_token_other

settings = LazySettings()

# 根据token获取存储到redis的用户信息数据,匹配到以后给scope添加用户信息
class TokenAuthMiddleware:
    def __init__(self, inner):
        self.inner = inner

    def __call__(self, scope):
        close_old_connections()
        try:
            query = parse.parse_qs(scope['query_string'].decode("utf-8"))['token'][0]
            if query:
                uid = get_token_other(query, 'id')
                if uid:
                    scope['user'] = u_account.objects.get(
                            uid=uid
                    )
            return self.inner(scope)
        except:
            __log = "websocket 认证失败"
            print(__log)
            return self.inner(scope)

TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))

console.py

#-*-coding:utf-8-*-
from channels.generic.websocket import AsyncWebsocketConsumer
from .custom import RedisMod

# 验证后如果scope种不包含用户则主动关闭
class ConsoleMsgConsumer(AsyncWebsocketConsumer):
    # 当WebSocket请求连接上时调用
    async def connect(self):
        if "user" not in self.scope:
            print("websocket 主动关闭")
            await self.close()
        else:
            await self.channel_layer.group_add(
                self.scope['user'].username,
                self.channel_name,
            )
            await self.accept()

    # 当WebSocket请求发来消息时
    async def receive(self, text_data=None, bytes_data=None):
        # if "user" not in self.scope:
        #     print("websocket connect close")
        #     await self.close()
        # else:
        await self.channel_layer.group_send(
            self.scope['user'].username,
            {
                'type': 'user.message',
                'message': text_data,
            }
        )

    # 当WebSocket请求断开连接时
    async def disconnect(self, code):
        if "user" in self.scope:
            await self.channel_layer.group_discard(
                self.scope['user'].username,
                self.channel_name
            )

    async def user_message(self, event):
        await self.send(event['message'])

 

 

views里使用

from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(user, {"type": "user.message", 'message': message})

 

VUE项目结构

-src

    --common

        --websocket.js

    --views

        --home.vue

websocket.js

export var message_data = []; //外部取数据的位置
export var filecmd_data = [];
export var connectStatus = false //重连判断

export function initWebpack(webUrl, token){//初始化websocket
 
  const wsuri = 'ws://'+webUrl+'?token='+token; 
  this.websock = new WebSocket(wsuri);//这里面的this都指向vue
  this.websock.onopen = websocketopen;
  this.websock.onmessage = websocketonmessage;
  this.websock.onclose = websocketclose;
  this.websock.onerror = websocketerror; 
}
function websocketopen(){//打开
  console.log("WebSocket连接成功", connectStatus)
  connectStatus = true
}

function websocketonmessage(e){ //数据接收
  var jdata = JSON.parse(e.data)
  if ( jdata["type"] == "filecmd" ) {
    filecmd_data.push(jdata)
  }
}
function websocketclose(){  //关闭
  console.log("WebSocket关闭", connectStatus);
  connectStatus = false
}
 function websocketerror(){  //失败
  console.log("WebSocket连接失败", connectStatus);
  connectStatus = false
}

export function close(){
  this.websock.close()//关闭websocket
  this.websock.onclose=function(e){
    console.log(e)//监听关闭事件
    console.log('关闭') 
  }
}

home.vue

import * as web from '../common/js/websocket'
methods:{
initWebsocket(){
 if (!this.hometimer){
  console.log("开始启动websocket")
  web.initWebpack('127.0.0.1:8000/websocket/console', sessionStorage.getItem('token'))
  this.hometimer = setInterval(function(){
    // console.log("web.message_data: ", web.message_data.length)
    console.log("websocket status: ", web.connectStatus)
    if (! web.connectStatus){
      console.log("websocket 断开重连")
      web.initWebpack('127.0.0.1:8000/websocket/console', sessionStorage.getItem('token'))
      web.connectStatus = true
    }
    if ( web.message_data.length != 0 ) {
      var data = web.message_data[0]
      web.message_data.splice(0, 1)
      console.log(web.message_data)
    }
  },10000)
 }
},
}

 

注:

1、django不适用与单用户多点登录

2、django重启后页面重连后关闭页面,redis里面没有被删除掉

 

 

 

 

转载于:https://my.oschina.net/u/3164044/blog/3073394

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值