从零开始搭建django前后端分离项目 系列四(实战之实时进度)
本项目实现了任务执行的实时进度查询
实现方式
前端websocket + 后端websocket + 后端redis订阅/发布
实现原理
任务执行后,假设用变量num标记任务执行的进度,然后将num发布为订阅的消息保存到redis队列,比如 redis_helper.public('当前任务进度为 %s' %num),django的websocket视图在特定频道订阅消息num并利用websocket协议将消息实时推送到前端,完成前端实时进度展示。
实现代码
redis订阅/发布:
class RedisHelper: def __init__(self, key): self.__conn = redis.Redis(host=config.host2, port=config.port2, db=config.db2) self.chan_sub = key self.chan_pub= key #发送消息 def public(self,msg): # logger.info(msg) self.__conn.publish(self.chan_pub,msg) return True #订阅 def subscribe(self): #打开收音机 pub = self.__conn.pubsub() #调频道 pub.subscribe(self.chan_sub) #准备接收 pub.parse_response() return pub
django视图:
@accept_websocket def analyze(request): if not request.is_websocket(): # 判断是不是websocket连接 file_path=request.GET.get('file_path') file_path_id = request.GET.get('file_path_id') file=File.objects.get_or_create(id=file_path_id)[0] jobname=file.name job = Job(name=jobname,file=file) job.save() channel = job.id result = cluster_analyze_task.delay(channel,file_path,file_path_id) taskid=result.id job.task_id=taskid job.save() return JsonResponse({'taskid': taskid,'channel': channel},safe=False) else: for message in request.websocket: obj = RedisHelper(message) redis_sub = obj.subscribe() while True: msg = redis_sub.parse_response() msg = msg[2] request.websocket.send(msg) # 发送消息到客户端 if msg.decode()=='end': break
前端websocket:
vue的method中增加如下方法: initWebSocket() { // 初始化weosocket // ws地址 const wsuri = 'ws://10.39.211.151:8000/app/analyze/'; this.websock = new WebSocket(wsuri); this.websock.onopen = this.websocketonopen; this.websock.onmessage = this.websocketonmessage; this.websock.onclose = this.websocketclose; }, websocketonmessage(e) { // 数据接收 // console.log(e.data); }, websocketsend(agentData) { // 数据发送 // 若是ws开启状态 if (this.websock.readyState === this.websock.OPEN) { this.websock.send(agentData) } // 若是 正在开启状态,则等待300毫秒 else if (this.websock.readyState === this.websock.CONNECTING) { let that = this;// 保存当前对象this setTimeout(function() { that.websock.send(agentData) }, 300); } // 若未开启 ,则等待500毫秒 else { this.initWebSocket(); let that = this;// 保存当前对象this setTimeout(function() { that.websock.send(agentData) }, 500); } }, websocketonopen() { // alert('数据发送中...'); console.log('WebSocket连接成功'); }, websocketclose(e) { // 关闭 console.log('connection closed (' + e.code + ')'); } 在创建时进行初始化 created() { this.initWebSocket(); },
效果图