Flask使用SocketIO实现WebSocket与Vue进行实时推送
作者:洲的学习笔记 发布时间:2023-02-19 05:05:45
前言
本文旨在记录使用Flask框架过程中与前端Vue对接过程中,存在WebSocket总是连接失败导致前端取不到数据的问题。以及在使用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’的问题!
如下图所示:只有三行控制台输出的记录、总是报错(该错在网上没有解决方法)等。
技术选型:前端Vue、后端Flask。
核心问题
需要着重注意的是,Flask框架中有原生的Websocket写法,也有对Websocket封装之后的依赖包SocketIO写法,所以在进行与前端对接的过程中,需要与前端对接好接口标准。在本次项目中,后端最开始用的是封装好WebSocket后的socketio进行编写,而前端使用了原生的websocket-vue写法,导致一直对接不上,获取不到数据。以及所有的报错或者各种bug问题,笔者都推测是跟gevent-websocket这个包有关。
在前端更改为vue-socketio之后,成功解决对接失败问题。(也可以后端改用原生写法,总之两边需要同时使用一个标准。)前端Vue可以参考Vue的文档去看使用哪种写法即可。
Flask的原生WebSocket(flask-sockets)与封装SocketIO
Flask-Sockets和Flask-SocketIO之间的主要区别在于前者仅仅将WebSocket协议(通过使用gevent-websocket项目)进行包装,因此它只适用于原生支持WebSocket协议的浏览器,对于那些不支持WebSocket协议的较老的浏览器,就无法使用它了。
Flask-SocketIO则不同,它不仅实现了WebSocket协议,并且对于那些不支持WebSocket协议的旧版浏览器,使用它也能够实现相同的效果。新版旧版的浏览器都能使用他。可以这么理解,flask把websocket功能封装在了socketio这个新的包里面。
另一个区别是Flask-SocketIO实现了SocketIO Javascript库公开的消息传递协议。
而Flask-Sockets只是实现通信通道,发送的是完全取决于应用程序。
1、Flask-SocketIO(封装写法)
使用SocketIO之前需要导入该包,即pip install flask-socketio。也可以直接在代码中import该包中的两个功能。
即:from flask_socketio import SocketIO, emit。
下面是服务端代码:(关于如何在实战中应用,可以看笔者上一篇关于flask博客中的代码实现,大致思路是使用线程)
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协议,而不是走的是ws,笔者推测是对ws进行了封装,导致最终走的是http协议。
//上面代码中的/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) #发送数据
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); # 接收数据
$("#time").html(content);
};
</script>
</body>
</html>
3、Bug 1:控制台输出没有Running on 127.0.0.1以及没有输出日志
在安装了gevent-websocket的这个包之后,会顺带安装gevent这个包,需要注意的是,gevent这个包会导致项目运行之后,控制台不会输出running on这个bug和 没有Log输出日志的bug。
经过笔者查证之后,发现是gevent-websocket这个包太老了,2017年的就已经停止更新了。所以这个包如果使用的话,会顺带导致一些对于新版本的Flask兼容性问题,所以导致了控制台的上述两个Bug存在。
解决方案:删掉gevent、gevent-websocket这两个包,可以下载 simple-websocket这个包来替代这两个包完成功能开发。
解决之后,控制台可以正常显示了。
4、Bug 2:显示连接错误。
在连接错误之后,推测这种报4的错误(网上全是3的错误),应该是没有安装gevent-websocket这个包,但是安装了之后又会造成第一类bug,所以可以直接安装simple-websocket这个依赖包。
参考文章:https://www.jb51.net/article/250776.htm
来源:https://blog.csdn.net/weixin_51484460/article/details/124538365


猜你喜欢
- 前言:在使用DDT数据驱动+HTMLTestRunner输出测试报告时遇到过2个问题:1、生成的测试报告中,用例名称后有dict() -&g
- 本文实例介绍了如何使用ASP代码来读写注册表,呵呵厉害吧! 一个例子: <%Dim ReadComputerNam
- defer用于资源的释放,会在函数返回之前进行调用。如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。def
- Sql Server的存储过程是一个被命名的存储在服务器上的Transacation-Sql语句集合,是封装重复性工作的一种方法,它支持用户
- MySQL Shell import_table数据导入1. import_table介绍这一期我们介绍一款高效的数据导入工具,MySQL
- 前言Windows10 在 UWP 应用中支持亚克力画刷,可以在部件的底部绘制亚克力效果的背景图。下面我们使用 QLabel 来模拟这个磨砂
- 今天继续给大家介绍MySQL相关知识,本文主要内容是MySQL外键约束详解。一、MySQL外键约束作用外键约束(Foreign Key)即数
- 在mysql的手册中已经对max_user_connections有一点说明,它是用来限制用户资源的,怎么限制用户资源呢?这里做了个小测试。
- 需求:将查询的两列数据导出到excel中 1.选择数据库,右键任务→导出数据,打开导入导出向导,单击下一步2.在打开的SQ
- js给span标签赋值的方法?一般有两种方法:第一种方法:输出html<body onload="s()">
- 本文实例讲述了Python tkinter事件高级用法。分享给大家供大家参考,具体如下:先来看看运行效果:完整实例代码:# -*- codi
- 分析慢查询1.查看慢SQL是否启用,查看命令:show variables like 'log_slow_queries';
- 链接的 target 属性怎么用 JS 来控制? 在HTML 4.0 Strict和XHTML 1.0 STRICT里不允许在<a&g
- 在前面的DRF系列教程中,我们以博客为例介绍了序列化器, 使用基于类的视图APIView和ModelViewSet开发了针对文章资源进行增删
- 简单的仿图片验证码,适合新手简单的仿图片验证码演示,很容易被破解,实用性不大,但拿出来给新手学习一下还是不错的:JScript.Asp代码示
- SQL Server发展至今,关于日期的格式的控制方法,有传统的方法,比如CONVERT(),也有比较便利的新方法,比如FORMAT();同
- SQL SERVER 2000安装教程:https://www.jb51.net/article/37380.htm1、如果您的SQL空间开
- 在实际开发中经常会遇到计算某个字段的排名的情况如下表:totak_sales现在又如此要求:按sales的逆序排序,要求添加一个sales_
- 上一章节我们学习了 excel 的读取模块 - xlrd ,今天章节将学习 excel 的写入模块 - xlsxwriter 。通过该章节的
- 有时需要获取远程网站的某些信息,而服务器又限制了GET方式,只能通过POST数据提交,这个时候我们可以通过asp来实现模拟提交post数据,