服务端主动给客户端推送消息
在了解这个之前,先要知道ajax,队列和递归
from django.shortcuts import render,HttpResponse import json from django.http import JsonResponse # Create your views here. # 验证ajax def ab_dy(request): if request.method == 'post': back_dic = {'username':'tony'} # return HttpResponse(json.dumps(back_dic)) # 需要dataType参数 return JsonResponse((back_dic)) # 不需要dataType参数 return render(request,'ab_dy.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ajax验证</title> <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script> </head> <body> <button id="d1">提交</button> <script> $('#d1').click(function () { $.ajax({ url:'', # 后端服务地址 type:'post', # 请求方式 data:{}, # 发送的数据 {#dataType:'JSON',#} # 如果django后端是通过HttpResponse返回数据的那么不会自动返序列化,而如果是JsonResponse则会自动转化,该参数可以不指定 success:function (args) { alert(typeof args) # 执行成功之后需要进行的操作 异步回调 } }) }) </script> </body> </html>
队列:先进先出
import queue q = queue.Queue() # 创建一个队列 q.put('jason') # 朝队列中丢数据 q.put('egon') v1 = q.get() # 获取数据 v2 = q.get() # v3 = q.get() # 如果没有数据了,get方法默认会一直阻塞 try: v3 = q.get(timeout=3) # 等3秒 之后还没数据直接报错 queue.Empty except queue.Empty as e: print(e) print(v1,v2) # 注意该队列并不会用于实际生产 主要是用来做本地的测试 # 实际生产建议使用redis、kafka、rebittMQ
# python最大递归深度多少呀 997、998、... 官网说是1000 def func(): func() func() # 在js中 根本没有递归的概念 函数内部自己调用自己是可以的 属于正常事件范畴 function func1(){ $.ajax({ url:'', type:'get', data:{}, success:function(args){ func1() } }) } $(function(){ # 等待页面加载完毕之后执行函数内的代码 func1() })
让浏览器定时朝后端发送请求(通过ajax向后端偷偷发送数据),比如每隔五秒钟发一次请求,那么你的数据延迟就可能会高达五秒
不足之处:
数据延迟
消耗资源过大
请求次数太多
# 队列+ajax 服务端给每个客户端建立队列,让浏览器通过ajax朝服务端要数据,去各自的队列中获取 如果没有数据则会阻塞但是不会一直阻塞,比如阻塞你30秒,还没有数据则返回,然后让客户端浏览器再次发送请求数据的请求 相对于轮询 基本是没有消息延迟的 请求次数降低了很多 # web版本的qq和微信基本上用的都是这么一个逻辑
基于ajax及队列实现长轮询的功能
1.首页自定义用户唯一表示,给每个用户初始化一个队列 2.发送按钮绑定点击事件 后端讲数据放入每一个队列中 3.书写自动获取数据的ajax代码 循环调用 4.前端获取数据DOM操作渲染页面
#全局大字典 q_dict = {} # {'唯一标识':队列...} def ab_b1(request): # 获取自定义的客户端唯一标识 name = request.request.GET.get('name') # 给每一个客户端创建一个队列 q_dict[name] = queue.Queue() return render(request,'ab_b1.html',locals()) def send_msg(request): if request.method == 'post': # 获取用户发送的消息 content = request.POST.get('content') # 将该消息传递给所有的队列 for q in q_dict.values(): q.put(content) return HttpResponse('ok') def get_msg(request): name = request.GET.get('name') # 拿到对应的队列 q = q_dict.get(name) #将队列中可能又取出并返回给前端浏览器得数据 # 定义一个字典与ajax进行交互 back_dic = {'status':True,'msg':''} try: data = q.get(timeout=10) # 等10s 没有则直接报错 back_dic['msg'] = data except queue.Empty as e: back_dic['status'] = False return JsonResponse(back_dic)
$('#d1').click(function () { $.ajax({ url:'/send_msg/', type:'post', data:{'content':$('#d2').val()}, dataType:'JSON', success:function (args) { } }) }); function getMsg(){ $.ajax({ url:'/get_msg/', type:'get', data:{'name':'{{ name }}'}, // 只要当前登陆人的队列中的数据 {#dataType:'JSON',#} success:function (args) { // 针对返回的消息做相应的处理 if(args.status){ // 有消息则渲染页面 讲消息全局放到聊天纪录里面 // 1 创建标签 var pEle = $('<p>'); // 2 给标签设置文本内容 pEle.text(args.msg); // 3 讲创建好的标签添加到聊天记录div标签内 $('#content').append(pEle) }else{ // 没有消息 则继续发送 } getMsg() // 循环请求数据 } }) } $(function () { getMsg() // 等待页面加载完毕自动执行 })
真正的做到服务端发送消息而不再是被动的发送
""" HTTP协议 网络协议(不加密传输) HTTPS协议 网络协议(加密传输) 上面两个协议都是短链接 websocket网络协议 (加密传输) 浏览器和服务端创建链接之后 默认不再断开 两端都可以基于该链接收发消息 websocket的诞生能够真正做到服务端发送消息而不再是被动的发送 """
""" 分成两大部分 1.握手环节:验证服务端是否支持websocket协议 先连接服务器 浏览器产生一个随机字符串 给服务端发送一份(请求头) 自己留一份 Sec-WebSocket-Key: ePW8kp1XqLNWbJxE/Q38SA== 服务端和客户端都对随机字符串做下面的操作 随机字符串 + magic string拼接 然后再讲拼接好的结果进行加密处理(sha1/base64)的到密文 浏览器自动比对双方产生的密文是否一致,如果一致说明服务端支持websocket 如果不一致会报错 假设比对上了 建立websocket链接 基于该链接收发消息 2.收发数据 密文传输 >>> 必然要涉及解密(全球统一)的过程 基于网络传输的数据都是二进制格式 对应到我们python中就是bytes类型 数据解密过程 1.先读取数据的第二个字节的后7位(payload) 根据7位数据的大小来指定不同的解密流程 =127:再往后读取8个字节 =126:再往后读取2个字节 <=125:不再往后读取 除去前面读取的数据之外 再往后读4个字节(masking-key) 拿着它去解析后面的真实数据(依据一个计算公式) """