上一篇讲完了 Flask 的本体,这篇开始就要开始讲 Flask 的插件了。Flask 从初始版本(2010/04/01)发布以来,已经过去了 10 年左右,许多人为了能够更加快速的开发,贡献了需多方便使用的插件。而这篇要介绍第一个插件就是 — Flask-SocketIO。
讲到现在有没有发现 HTTP 协议的模式基本上是 Client 打一下回应一下,再打一下再回应一下,而现在如果 Server 端需要主动传资讯给 Client,就必须等使用者下一次打的时候,包再回应里面再回传给 Client。
早期各种网路应用还不发达的时候,也许并没有问题,但是现在各种各样的应用出来之後,这样的模式就有点不足了,所以就有了 WebSocket 这个东西,而 WebSocket 相比 HTTP 协议,WebSocket 有着以下的优点:
不过 WebSocket 只是协议,需要有一个程序去实作它,并且作为套件供其他程序使用,而且前後端都需要有个程序去实作,否则无法达成双向通讯。在前端处理这些东西的通常都是 JavaScript ,所以 JavaScript 中 WebSocket 的套件叫做 Socket.IO ,而在後端的 Flask 中也有相对应的套件,而那个套件就是这篇的主题 — Flask-SocketIO。
总而言之
WebSocket -> 协议
Socket.IO -> JavaScript 的前端实作
Flask-SocketIO -> Flask 框架的後端实作
大概就酱
首先,因为是插件,所以并没有包含在 Flask 里面,需要另外安装。当然还是使用我们熟悉的 pip 来安装啦,不过除了安装 Flask-SocketIO 以外,还要安装 Flask-SocketIO 依赖的非同步服务 eventlet。
$ pipenv install flask-socketio eventlet
既然说到了安装,那就先来说一下後端如何使用好了(因为前端的话只要使用 JavaScript 然後透过 CDN 导入就可以了),假设现在要做一个超简单的聊天室(终於不是拿前面的那坨来改了,记得 pipenv install flask
喔),架构长这样(虽然不是拿前面那坨改,但是还是有几个可以复制过来沿用):
ithome_chatroom
├── templates
│ └── index.html # 聊天室首页
├── app.py # 主要的档案(很烂的形容我知道,我就不会形容啊)
├── configs.py # 设定档
├── Pipfile # 不管它,建立虚拟环境时自己会出现
└── Pipfile.lock # 不管它,安装套件时自己会出现
首先当然是做好聊天室後端啦,後端当然是写在 app.py
里面。
app.py
from flask import Flask, render_template
from flask_socketio import SocketIO # 加上这行
import configs
app = Flask(__name__)
app.config.from_object(configs)
socketio = SocketIO(app) # 加上这行
@app.route('/')
def index():
return render_template('index.html')
@socketio.on('send')
def chat(data):
socketio.emit('get', data)
@socketio.on('test')
def test():
socketio.send("test")
if __name__ == "__main__":
socketio.run(app)
处理好後端之後呢,接着当然就是前端啦,不过前端有点特殊,刚刚前面讲过前端需要有个程序来处理,不过这个架构上看起来并没有前端的处理程序阿?那是因为前端的处理程序可以在渲染前端时,透过 CDN 导入後在执行,而只需要在 .html
档里面加上一句就可以了(不是我偷懒不讲啦,只是弄个小小的实验而已没必要搞得这麽复杂啦)。
那要怎麽找 CDN 来导入呢?可以从下面两个(Socket.IO 是必要的,JQuery 可以不必,只是因为我喜欢用 JQuery 而已,没办法,JavaScript 语法太长了)连结进去,找到随便一个版本(我推荐是用红色背景的那个),然後找到 </>
这样的案件,点下去就复制好了。
复制好了之後,来到 index.html
贴上,再加上几行就 OK 了。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>WebSocket test</title>
<!-- JQuery 的 CDN 连结 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Socket.IO 的 CDN 连结 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"
integrity="sha512-WL6WGKMPBiM9PnHRYIn5YEtq0Z8XP4fkVb4qy7PP4vhmYQErJ/dySyXuFIMDf1eEYCXCrQrMJfkNwKc9gsjTjA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Socket.IO 的使用 -->
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
// Socket.IO Start connect
var socket = io.connect();
// Socket.IO send message
$("#send").click(function (e) {
// Send message
socket.emit('send', $('#message').val())
// Clear input field
$('#message').val('')
});
// Socket.IO get message
socket.on('get', function (data) {
$('#chat_content').append('<p>I say: ' + data + '</p>');
});
// Socket.IO get test
socket.on("message", function (data) {
$('#chat_content').append('<p>System : ' + data + '</p>');
});
// Socket.IO send test
$("#test").click(function (e) {
socket.emit('test')
});
});
</script>
</head>
<body>
<h1>Hello</h1>
<h2>WebSocket test</h2>
<form>
<fieldset>
<legend>Message</legend>
<input type="text" id="message" name="message" />
<input type="button" id="send" value="Send" />
<input type="button" id="test" value="Test" />
</fieldset>
</form>
<hr />
<div id='chat_content'></div>
</body>
</html>
这样子输入完就可以了,简单来说 send
跟 emit
可以传送事件,其中send
是传送未命名事件;而 emit
是传送命名事件。on
则是监听有无事件发生。
那就来看执行後会发生什麽事吧。
看起来没有发生什麽对吧,再 input 输入一点东西後按下 Send 看看。
如果再按下旁边的 Test 呢?
是不是没有看出来哪里厉害对吧,同时开两个分页再重复上面的操作後你就懂了。
那麽就大概这样,WebSocket 还有很多可以说的,但是如果全部塞在同一篇的话就太多了,而且我後面还有其他插件要说,所以 WebSocket 就先介绍到这里。
大家掰~掰~
>>: Day22 - Shioaji X Backtesting -双均线策略
Q: 同事说自己的 C++ 能力是世界第一,怎麽样可以让他意识到自己没那麽厉害? A: 实不相瞒,...
储存前,验证资料正确性 当使用者输入资料後需要验证资料正确性,并提示给使用者。在VoK要做到这点非常...
随着资讯技术普及与推陈布新,基础设施及服务(IaaS)、平台即服务(PaaS)、软件即服务(Saa...
回圈 loop 昨天小光更进一步的认识了逻辑判断式,也开始自己开发了一个心情显示器,不过如果要表现1...
在资料库管理上,root 相当於拥有所有权限的最大管理者,针对不同使用者规划给予相应的权限是很重要的...