Vue+Django+Channles实现websocket

本文介绍了如何结合Vue.js前端和Django后端,利用Channels库来实现WebSocket通信。详细阐述了Django项目的设置,包括`settings.py`, `asgi.py`, `routing.py`的配置,以及在Django的`views`中使用WebSocket的相关代码。同时,展示了Vue项目结构,特别是`src/common/websocket.js`中的WebSocket连接和`views/home.vue`中如何调用WebSocket。需要注意的是,Django不适用于单用户的多点登录场景,并且在Django重启后,页面重新连接,Redis中的连接信息不会被自动清除。" 117806810,10292936,HTML5/CSS3实现线条进度条,双色渐变效果,"['HTML', 'CSS3', '前端开发', '动画效果', 'jQuery']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue+Django+Channles实现websocket

Django端

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端

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里面没有被删除掉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值