本文介绍Flask中websocket功能,下面用实现“服务端主动向前端推送消息”功能来详细介绍:
技术栈如下:

  • 前端: Vue2.0 + element-ui

  • 后台: Flask

一、后端代码实现

1、创建websocket

# 创建Flask App
app = create_app(DevelopConfig)
# 跨域请求
CORS(app, supports_credentials=True)

# 创建WebSocket,用于服务器主动向web端推送消息,避免web端轮询查询
sockets = Sockets(app)

2、保存websocket连接

定义一个字典ws_dict,保存websocket连接

ws_dict = {}

说明:

  • websocket连接对象的地址字符串作为key
  • {‘ws’: ws, ‘message’: []}作为值,其中ws是websocket连接对象
  • 判断‘message’对应的值不为空就发送消息,发送完成后就清空

3、代码实现

@sockets.route('/echo')
def echo_socket(ws):
    key = str(ws).split(' ')[-1].rstrip('>')  # 用作服务器给web端推送的标识
    if key not in ws_dict:
        ws_dict[key] = {'ws': ws, 'message': [{'msg': '测试推送服务端推送websocket消息'+key}]}

    while not ws.closed:
        message = ws.receive()  # 接收到消息
        if message is not None:
            sendmsg = ws_dict.get(key, {}).get('message')
            if sendmsg:  # 消息不为空时推送
                ws.send(json.dumps(sendmsg[0], ensure_ascii=False))  # 主动给客户端推送消息
                ws_dict[key]['message'] = []

# flask启动配置
def start_flask():
	from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('0.0.0.0', 5000), app, handler_class=WebSocketHandler)
    logging.info('server start')
    server.serve_forever()

说明:

  • 服务端必须接收到客户端发的消息才能保持该服务运行
  • 如果ws.receive()没有接收到客户端发送的消息,那么它会关闭与客户端建立的链接
  • 底层解释:Read and return a message from the stream. If None is returned, then the socket is considered closed/errored.
  • 所以客户端只建立连接,不与服务端交互通信,则无法实现自由通信状态。
  • 要实现推送消息,只需要往ws_dict里面根据key填充数据,发送完消息后清空数据

二、前端代码实现

1、在main.js中添加如下代码

var gWebSocket = null;
var gWsConn = false;

function isJSONStr(str) {
    if (typeof str == 'string') {
        try {
            var obj=JSON.parse(str);
            if(typeof obj == 'object' && obj ){
                return true;
            }else{
                return false;
            }
        } catch(e) {
            console.log('error:'+str+'!!!'+e);
            return false;
        }
    }
	
	return false;
}

function initWebsocket() {
	if ("WebSocket" in window) {
		if (gWebSocket == null) {
			var gWsUrl = `ws://127.0.0.1:5000/echo`;
			gWebSocket = new WebSocket(gWsUrl);
		}
		
		gWebSocket.onopen = function() {
            // Web Socket 已连接上,使用 send() 方法发送数据
            console.log("websocket已连接...");
			gWsConn = true;
        };
		
		gWebSocket.onmessage = function(evt) {
			console.log("接收数据:" + evt.data);
			if (isJSONStr(evt.data)) {
				var jsonObj = JSON.parse(evt.data);
				sessionStorage.setItem('wskey', jsonObj['wskey']);
			}
		};
		
		gWebSocket.onclose = function() {
            // 关闭 websocket
            console.log("连接已关闭...");
			gWebSocket = null;
			gWsConn = false;
        };
	} else {
        alert("您的浏览器不支持 WebSocket!");
    }
}

var initTimer = setInterval(function() {//定时检测websocket连接
	if (!gWsConn) {//初始化websocket
		initWebsocket();
		console.log('Try to connect server...');
	} else {
		//window.clearInterval(initTimer);
		let username = sessionStorage.getItem('username');
		if (username != null) {
			gWebSocket.send(JSON.stringify({"username":username}));
		}
	}
}, 5000);

2、登录成功后保存用户信息

async login() {
	if (this.form.username == "" || this.form.password == "") {
		this.$message({
			message: '请输入用户名和密码',
			type: 'warning'
		});
	} else {
		let argc = {
			'username': this.form.username,
			'password': this.form.password
		};

		let result = await this.$fetchPost('/login', argc);
		if (result.status == 200) {
			console.log(result.data);
		const { groups, roles, msg, code } = result.data;
		console.log(groups, roles, msg, code);
		if (result.data.code == '0') {
			let groups = '{"首页": [], "业务菜单": ["3D模型", "画图展示", "业务3"], "系统设置": ["用户管理", "系统日志"]}';
			let roles = '{"首页": ["读"], "3D模型": ["读", "写"], "业务2": ["读", "写"], "业务3": ["读", "写"], "用户管理": ["读", "写"], "系统日志": ["读", "写"]}';
			sessionStorage.setItem('record', this.form.record);
			sessionStorage.setItem('username', this.form.username);
			this.$store.commit('setData', {
				'access_token': this.form.username,
				'userInfo': this.form.username,
				'groups': this.$isJSONStr(groups) ? JSON.parse(groups) : {},
				'roles': this.$isJSONStr(roles) ? JSON.parse(roles) : {},
			});
			this.$router.push('/home');
			this.form.password = '';
		} else {
			this.$message({
				message: result.data.msg,
				type: 'warning'
			});
		}
		}
	}
}

登录成功后把用户信息保存到sessionStorage里面,=根据sessionStorage里有无用户信息判断是否发送websocket请求。

三、完整教程地址

Flask搭建项目完整教程:Flask+Vue搭建系统

Logo

前往低代码交流专区

更多推荐