Flask使用SocketIO實現(xiàn)WebSocket與Vue進行實時推送
前言
本文旨在記錄使用Flask框架過程中與前端Vue對接過程中,存在WebSocket總是連接失敗導致前端取不到數(shù)據(jù)的問題。以及在使用WebSocket相關功能的庫包gevent-websocket之后,導致運行Flask項目之后,控制臺沒有顯示running on 127.0.0.1:5000 問題、以及沒有輸出log日志記錄的問題、以及總是報錯Websocket connection to‘ws://127.0.0.1:5000/socket.io/?EIO=4&transport=websocket’failed:Error during Websocket handshake:Unexpected response code:400’的問題!
如下圖所示:只有三行控制臺輸出的記錄、總是報錯(該錯在網(wǎng)上沒有解決方法)等。
技術選型:前端Vue、后端Flask。
核心問題
需要著重注意的是,F(xiàn)lask框架中有原生的Websocket寫法,也有對Websocket封裝之后的依賴包SocketIO寫法,所以在進行與前端對接的過程中,需要與前端對接好接口標準。在本次項目中,后端最開始用的是封裝好WebSocket后的socketio進行編寫,而前端使用了原生的websocket-vue寫法,導致一直對接不上,獲取不到數(shù)據(jù)。以及所有的報錯或者各種bug問題,筆者都推測是跟gevent-websocket這個包有關。
在前端更改為vue-socketio之后,成功解決對接失敗問題。(也可以后端改用原生寫法,總之兩邊需要同時使用一個標準。)前端Vue可以參考Vue的文檔去看使用哪種寫法即可。
Flask的原生WebSocket(flask-sockets)與封裝SocketIO
Flask-Sockets和Flask-SocketIO之間的主要區(qū)別在于前者僅僅將WebSocket協(xié)議(通過使用gevent-websocket項目)進行包裝,因此它只適用于原生支持WebSocket協(xié)議的瀏覽器,對于那些不支持WebSocket協(xié)議的較老的瀏覽器,就無法使用它了。
Flask-SocketIO則不同,它不僅實現(xiàn)了WebSocket協(xié)議,并且對于那些不支持WebSocket協(xié)議的舊版瀏覽器,使用它也能夠實現(xiàn)相同的效果。新版舊版的瀏覽器都能使用他??梢赃@么理解,flask把websocket功能封裝在了socketio這個新的包里面。
另一個區(qū)別是Flask-SocketIO實現(xiàn)了SocketIO Javascript庫公開的消息傳遞協(xié)議。
而Flask-Sockets只是實現(xiàn)通信通道,發(fā)送的是完全取決于應用程序。
1、Flask-SocketIO(封裝寫法)
使用SocketIO之前需要導入該包,即pip install flask-socketio。也可以直接在代碼中import該包中的兩個功能。
即:from flask_socketio import SocketIO, emit。
下面是服務端代碼:(關于如何在實戰(zhàn)中應用,可以看筆者上一篇關于flask博客中的代碼實現(xiàn),大致思路是使用線程)
from flask import Flask, render_template from flask_socketio import SocketIO, emit app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socketio = SocketIO(app) @app.route('/') def index(): return render_template('index.html') @socketio.on('my event', namespace='/test') def test_message(message): emit('my response', {'data': message['data']}) @socketio.on('my broadcast event', namespace='/test') def test_message(message): emit('my response', {'data': message['data']}, broadcast=True) @socketio.on('connect', namespace='/test') def test_connect(): emit('my response', {'data': 'Connected'}) @socketio.on('disconnect', namespace='/test') def test_disconnect(): print('Client disconnected') if __name__ == '__main__': socketio.run(app)
而對于js來說,客戶端代碼十分簡單,直接上代碼:(注意是socketio的標準)
$(document).ready(function(){ var socket = io.connect('http://' + document.domain + ':' + location.port + '/test'); //注意如果使用var socket = io.connect(location.protocol + ‘//' + document.domain.....的寫法,這里的protocol是http協(xié)議,而不是走的是ws,筆者推測是對ws進行了封裝,導致最終走的是http協(xié)議。 //上面代碼中的/test 就是namespace socket.on('my response', function(msg) { $('#log').append('<p>Received: ' + msg.data + '</p>'); });. $('form#emit').submit(function(event) { socket.emit('my event', {data: $('#emit_data').val()}); return false; }); $('form#broadcast').submit(function(event) { socket.emit('my broadcast event', {data: $('#broadcast_data').val()}); return false; }); });
2、Flask-Sockets(原生Websocket寫法)
服務端:
from flask import Flask from flask_sockets import Sockets import datetime import time import random app = Flask(__name__) sockets = Sockets(app) @sockets.route('/echo') def echo_socket(ws): while not ws.closed: now = datetime.datetime.now().isoformat() + 'Z' ws.send(now) #發(fā)送數(shù)據(jù) time.sleep(1) @app.route('/') def hello(): return 'Hello World!' if __name__ == "__main__": from gevent import pywsgi from geventwebsocket.handler import WebSocketHandler server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler) print('server start') server.serve_forever()
客戶端代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script> </head> <body> <div id="time" style="width: 300px;height: 50px;background-color: #0C0C0C; color: white;text-align: center;line-height: 50px;margin-left: 40%;font-size: 20px"></div> <script> var ws = new WebSocket("ws://127.0.0.1:5000/echo"); #連接server //這是websocket的前端原生寫法,直接連接ws。 ws.onmessage = function (event) { content = document.createTextNode(event.data); # 接收數(shù)據(jù) $("#time").html(content); }; </script> </body> </html>
3、Bug 1:控制臺輸出沒有Running on 127.0.0.1以及沒有輸出日志
在安裝了gevent-websocket的這個包之后,會順帶安裝gevent這個包,需要注意的是,gevent這個包會導致項目運行之后,控制臺不會輸出running on這個bug和 沒有Log輸出日志的bug。
經(jīng)過筆者查證之后,發(fā)現(xiàn)是gevent-websocket這個包太老了,2017年的就已經(jīng)停止更新了。所以這個包如果使用的話,會順帶導致一些對于新版本的Flask兼容性問題,所以導致了控制臺的上述兩個Bug存在。
解決方案:刪掉gevent、gevent-websocket這兩個包,可以下載 simple-websocket這個包來替代這兩個包完成功能開發(fā)。
解決之后,控制臺可以正常顯示了。
4、Bug 2:顯示連接錯誤。
在連接錯誤之后,推測這種報4的錯誤(網(wǎng)上全是3的錯誤),應該是沒有安裝gevent-websocket這個包,但是安裝了之后又會造成第一類bug,所以可以直接安裝simple-websocket這個依賴包。
參考文章:http://www.dbjr.com.cn/article/250776.htm
到此這篇關于Flask使用SocketIO實現(xiàn)WebSocket與Vue進行實時推送的文章就介紹到這了,更多相關Flask Vue 實時推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 一文詳解websocket在vue2中的封裝使用
- Vue項目中Websocket的使用實例
- 前端之vue3使用WebSocket的詳細步驟
- vue3.0中使用websocket,封裝到公共方法的實現(xiàn)
- vue3+ts+Vuex中使用websocket協(xié)議方式
- Vue項目使用Websocket大文件FileReader()切片上傳實例
- vue項目使用websocket連接問題及解決
- Vue?websocket封裝實現(xiàn)方法詳解
- vue使用websocket概念及示例
- vue基于websocket實現(xiàn)智能聊天及吸附動畫效果
- vue+flv.js+SpringBoot+websocket實現(xiàn)視頻監(jiān)控與回放功能
- vue項目中使用websocket的實現(xiàn)
- vue 項目中使用websocket的正確姿勢
- vue實現(xiàn)websocket客服聊天功能
- Vue+Websocket簡單實現(xiàn)聊天功能
- vue使用WebSocket模擬實現(xiàn)聊天功能
- websocket+Vuex實現(xiàn)一個實時聊天軟件
- 使用WebSocket+SpringBoot+Vue搭建簡易網(wǎng)頁聊天室的實現(xiàn)代碼
相關文章
Elasticsearches之python使用及Django與Flask集成示例
這篇文章主要為大家介紹了Elasticsearches之python使用及Django與Flask集成示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04Django查詢數(shù)據(jù)庫的性能優(yōu)化示例代碼
這篇文章主要給大家介紹了關于Django查詢數(shù)據(jù)庫性能優(yōu)化的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2017-09-09使用Python OpenCV為CNN增加圖像樣本的實現(xiàn)
這篇文章主要介紹了使用Python OpenCV為CNN增加圖像樣本的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-06-06