iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0

上一篇講完了 Flask 的本體,這篇開始就要開始講 Flask 的插件了。Flask 從初始版本(2010/04/01)發布以來,已經過去了 10 年左右,許多人為了能夠更加快速的開發,貢獻了需多方便使用的插件。而這篇要介紹第一個插件就是 — Flask-SocketIO。

講到現在有沒有發現 HTTP 協議的模式基本上是 Client 打一下回應一下,再打一下再回應一下,而現在如果 Server 端需要主動傳資訊給 Client,就必須等使用者下一次打的時候,包再回應裡面再回傳給 Client。

早期各種網路應用還不發達的時候,也許並沒有問題,但是現在各種各樣的應用出來之後,這樣的模式就有點不足了,所以就有了 WebSocket 這個東西,而 WebSocket 相比 HTTP 協議,WebSocket 有著以下的優點:

  1. 支援雙向通訊(超重要,我就是要講它)。
  2. 建立連線後,WebSocket 客戶端、服務端資料交換時,資料包標頭較小。
  3. 支援擴充套件。

不過 WebSocket 只是協議,需要有一個程式去實作它,並且作為套件供其他程式使用,而且前後端都需要有個程式去實作,否則無法達成雙向通訊。在前端處理這些東西的通常都是 JavaScript ,所以 JavaScript 中 WebSocket 的套件叫做 Socket.IO ,而在後端的 Flask 中也有相對應的套件,而那個套件就是這篇的主題 — Flask-SocketIO。

總而言之

WebSocket -> 協議
Socket.IO -> JavaScript 的前端實作
Flask-SocketIO -> Flask 框架的後端實作

大概就醬

Flask-SocketIO 使用

首先,因為是插件,所以並沒有包含在 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 語法太長了)連結進去,找到隨便一個版本(我推薦是用紅色背景的那個),然後找到 </> 這樣的案件,點下去就複製好了。

Socket.IO 的 CDN

JQuery 的 CDN

複製好了之後,來到 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>

這樣子輸入完就可以了,簡單來說 sendemit 可以傳送事件,其中send 是傳送未命名事件;而 emit 是傳送命名事件。on 則是監聽有無事件發生。

那就來看執行後會發生什麼事吧。

看起來沒有發生什麼對吧,再 input 輸入一點東西後按下 Send 看看。

如果再按下旁邊的 Test 呢?

是不是沒有看出來哪裡厲害對吧,同時開兩個分頁再重複上面的操作後你就懂了。

那麼就大概這樣,WebSocket 還有很多可以說的,但是如果全部塞在同一篇的話就太多了,而且我後面還有其他插件要說,所以 WebSocket 就先介紹到這裡。

大家掰~掰~


上一篇
Day 21 Flask Blueprint
下一篇
Day 23 Flask-Login
系列文
月光下的Flask之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言