1、輪詢
在一些須要進行實時查詢的場景下應用
好比投票系統:
你們一塊兒在一個頁面上投票
在不刷新頁面的狀況下,實時查看投票結果css
一、後端代碼
from flask import Flask, render_template, request, jsonify app = Flask(__name__) USERS = { 1: {'name': '小米', 'count': 300}, 2: {'name': '小康', 'count': 200}, 3: {'name': '小明', 'count': 600}, } @app.route('/') def index(): return render_template('Poll.html', users=USERS) @app.route('/vote', methods=['POST']) def vote(): # 接收uid,經過uid給票數 +1 # 用戶提交Json數據過來,用request.json獲取 uid = request.json.get('uid') USERS[uid]['count'] += 1 return "投票成功" @app.route('/get_vote') def get_vote(): # 返回users數據 # jsonify 是flask自帶的序列化器 return jsonify(USERS) if __name__ == '__main__': app.run()
二、前端代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>投票系統</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <style> .my-li { list-style: none; margin-bottom: 20px; font-size: 18px; } </style> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>最帥男人投票</h1> {% for (uid, user) in users.items() %} <button class="btn btn-success" onclick="vote({{ uid }})">投票</button> <li class="list-group-item-info my-li" id="{{ uid }}">{{ user.name }}目前的票數是: {{ user.count }}</li> {% endfor %} </div> </div> </div> <script> // 投票 function vote(uid) { // 向後端發送投票請求 axios.request({ url: '/vote', method: 'post', data: { uid: uid } }).then(function (response) { console.log(response.data); }) } // 獲取最新的投票結果 function get_vote() { axios.request({ url: '/get_vote', method: 'get' }).then(function (response) { // 獲取後端傳過來的新數據 // 從新渲染頁面 let users = response.data; for (let uid in users) { //根據uid獲取li標籤 改變innerText let liEle = document.getElementById(uid); liEle.innerText = `${users[uid]['name']}目前的票數是: ${users[uid]['count']}` } }); } // 頁面加載完後,馬上獲取數據 window.onload = function () { setInterval(get_vote, 2000) } </script> </body> </html>
三、輪詢
特色:每隔一段時間不斷向後端發送請求
缺點:消耗大 有延遲html
2、長輪詢
因爲上面的輪詢是不能實時查看到投票狀況的,存在必定的延遲性
長輪詢能夠實現實時查看投票狀況前端
一、後端代碼
from flask import Flask, render_template, request, jsonify, session import uuid import queue app = Flask(__name__) app.secret_key = '切克鬧' USERS = { 1: {'name': '小米', 'count': 300}, 2: {'name': '小康', 'count': 200}, 3: {'name': '小明', 'count': 600}, } Q_DICT = { # uid: q對象 } @app.route('/') def index(): # 模擬用戶登陸 # 模擬用戶登陸後的惟一id user_id = str(uuid.uuid4()) # 每一個用戶都有本身的Q對象 Q_DICT[user_id] = queue.Queue() # 把用戶的id存到session session['user_id'] = user_id # 頁面展現投票的人的信息 return render_template('longPoll.html', users=USERS) @app.route('/vote', methods=['POST']) def vote(): # 處理投票,給票數 +1 # 用戶提交Json數據過來,用request.json獲取 uid = request.json.get('uid') USERS[uid]['count'] += 1 # 投票成功後,給每一個用戶的Q對象put最新的值進去 for q in Q_DICT.values(): q.put(USERS) return "投票成功" @app.route('/get_vote') def get_vote(): # 請求進來,從session獲取用戶的id user_id = session.get('user_id') # 根據用戶的id 獲取用戶的Q對象 q = Q_DICT.get(user_id) # try: # ret = q.get(timeout=30) # except queue.Empty: # ret = '' ret = q.get() return jsonify(ret) if __name__ == '__main__': app.run()
二、前端代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>投票系統</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <style> .my-li { list-style: none; margin-bottom: 20px; font-size: 18px; } </style> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>最曬男人投票</h1> {% for (uid, user) in users.items() %} <button class="btn btn-success" onclick="vote({{ uid }})">投票</button> <li class="list-group-item-info my-li" id="{{ uid }}">{{ user.name }}目前的票數是: {{ user.count }}</li> {% endfor %} </div> </div> </div> <script> // 投票 function vote(uid) { // 向後端發送投票請求 axios.request({ url: '/vote', method: 'post', data: { uid: uid } }).then(function (response) { console.log(response.data); }) } // 獲取最新的投票結果 function get_vote() { axios.request({ url: '/get_vote', method: 'get' }).then(function (response) { // 判斷後端的數據是否爲空 if (response.data != '') { // 獲取到最新的數據 let users = response.data; for (uid in users) { // 根據uid找到每一個li標籤 let liEle = document.getElementById(uid); // 給每一個li標籤設置最新的數據 liEle.innerText = `${users[uid]['name']}目前的票數是: ${users[uid]['count']}` } } // 獲取完數據後,再發送請求,看還有沒有人投票,有的話再去獲取最新的數據 get_vote() }); } // 頁面加載完後,馬上獲取數據 window.onload = function () { get_vote() } </script> </body> </html>
三、長輪詢
特色:知足實時更新
缺點:消耗大
實現:
利用queue對象實現請求夯住
每一個請求進來都要生成一個q對象
若是有人投票 給全部的q對象put數據
拿數據請求從本身的q對象get數據 ios
3、websocket
一、介紹
http協議
短鏈接 無狀態 基於TCP/UDP協議進行傳輸數據(TCP/UDP: 傳輸協議)web
socket
socket不是傳輸協議 跟websocket是兩個徹底不同的東西 socket是套接字 API接口npm
websocket
H5出的新協議 瀏覽器和服務器只須要完成一次握手,二者之間就直接能夠建立持久性的鏈接,並進行雙向數據傳輸
解決輪詢問題
特色:
1. 握手 基於HTTP進行握手(所以websocket與Http有必定的交集,但不是同一個東西)
2. 發送數據加密
3. 保持鏈接不斷開json
二、在Flask中使用websocket
1. Flask沒有websocket,須要安裝包 pip install gevent-websocket 2. 後端怎樣創建一個支持websocket協議鏈接 from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer # 拿到websocket對象 ws = request.environ.get("wsgi.websocket") # 後端發送數據 ws.send(xxx) # 後端接收數據 ws.receive() if __name__ == '__main__': # app.run() # 即支持HTTP 也支持websocket http_server = WSGIServer(('0.0.0.0', 5000), app, handler_class=WebSocketHandler) http_server.serve_forever() 3. 前端怎麼發起websocket鏈接 let ws = new WebSocket("ws://127.0.0.1:5000") # 前端發送數據 ws.send("xxx") # 前端接收數據 ws.onmessage = function(event){ # 從接受的對象中獲取數據 let data = event.data } 4. 收發消息 1, 前端發送數據給後端 前端發送:ws.send('數據') 後端接收:ws.receive() 2, 後端發送數據給前端 後端發送:ws.send('數據') 前端接收的是對象:ws.onmessage = function(event){ let data = event.data }
三、Demo
1.後端
from flask import Flask, render_template, request from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json app = Flask(__name__) USERS = { 1: {'name': '小米', 'count': 300}, 2: {'name': '小康', 'count': 200}, 3: {'name': '小明', 'count': 600}, } WEBSOCKET_LIST = [] @app.route('/') def index(): return render_template('websocket.html', users=USERS) @app.route('/vote') def vote(): # 處理websocket # 判斷是什麼類型的請求,HTTP仍是websocket # 看可否獲取獲得websocket的對象 ws = request.environ.get("wsgi.websocket") if not ws: return "這是HTTP協議的請求" # 把全部用戶的ws對象存到一個列表 WEBSOCKET_LIST.append(ws) while True: # 獲取前端傳過來的uid,給打野票數 +1 uid = ws.receive() # 若是前端主動斷開鏈接 # 那麼後端也關閉與前端的鏈接 if not uid: WEBSOCKET_LIST.remove(ws) ws.close() break uid = int(uid) USERS[uid]["count"] += 1 data = { "uid": uid, "name": USERS[uid]["name"], "count": USERS[uid]["count"] } for ws in WEBSOCKET_LIST: # 給前端發送新的數據 ws.send(json.dumps(data)) if __name__ == '__main__': # app.run() # 這樣啓服務的意思是:即支持HTTP協議,也支持websocket協議 http_server = WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler) http_server.serve_forever()
2.前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>投票系統</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <style> .my-li { list-style: none; margin-bottom: 20px; font-size: 18px; } </style> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>最曬男人投票</h1> {% for (uid, user) in users.items() %} <button class="btn btn-success" onclick="vote({{ uid }})">投票</button> <li class="list-group-item-info my-li" id="{{ uid }}">{{ user.name }}目前的票數是: {{ user.count }}</li> {% endfor %} </div> </div> </div> <script> // 向後端發送一個websocket鏈接請求 let ws = new WebSocket('ws://127.0.0.1:5000/vote'); function vote(uid) { // 向後端發數據 ws.send(uid) } ws.onmessage = function (event) { let data = JSON.parse(event.data); let liEle = document.getElementById(data.uid); liEle.innerText = `${data.name}目前的票數是: ${data.count}` } </script> </body> </html>