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