【python】FlaskでSSE(Server-Sent Events)を実装する

こんばんは
今回はたまたまSSEを実装する機会があったのでそれと同時に
メモ的な感じで書いていきたいと思います。あとflaskのSSEの記事が少ないように感じたので

てなわけでどうぞ

SSEってなんぞや

ってところから始まりますが、飛ばしてもいいです。とばしたいならとばせ

まあ簡単にいうと、webサーバーからリアルタイムでレスポンスを受け取ることができる何ともexcitingな機能です。
実装もそれなりに簡単で、longpollingよりも効率がいいのでこれにしました。
まあwebsocketっていうやつもあるんだけど難しいので後回しにした

プログラミングって難しいよね

ちなみにlongpollingとwebsocketもおさらいしておきましょうかね。文章が多くなってSEO対策になr(((

じゃあSSEはどうなんだっていうとまあlongpollingとwebsocketを足して2で割ったような感じですかね。

まあ実装も難しくなく、サーバーにもあまり負荷がかかりません。

クライアントからサーバーにデータを送ることができませんがそれは普通にget通信やpostで代用できます。

sse


実装

ソースコードをどうぞ。ソースコード目的の人の方が多いと思うので。

ディレクトリ

dir/
|
|--main.py
|--templates
    |--index.html


main.py
                    
from flask import *
import time

app = Flask(__name__)

@app.route("/")
def main_page():
    return render_template("index.html")

@app.route("/sse")
def sse():
    resp = make_response()
    resp.headers["Content-Type"] = "text/event-stream"
    resp.response = sse_make()
    return resp

def sse_make():
    for i in range(10):
        yield "data: {0} {1}".format(str(i),"\n\n")
        time.sleep(1)
    pass


if __name__ == "__main__":
    app.run(port=5000)
    pass

                    
            

templates/index.html
                    
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
    <script>
        var es = new EventSource('/sse');

        es.addEventListener('message', function (event) {
            console.log(event.data);
        });
    </script>
</body>
</html>
                    
            

実行

準備が出来たら適当に実行して
http://localhost:5000/

に、デベロッパーツールのConsoleを開いた状態でアクセスしてみてください。
すると数字が一つずつ、デベロッパーツールに1秒おきに流れてくるはずです
一気に数字が表示されたら諦めてください


(いらない)解説

まず、main.pyの方からです。

main.py
                    
resp.headers["Content-Type"] = "text/event-stream"
                    
            
ここではヘッダーのContent-Typeをtext/event-streamに指定しているのですが、
これは「これからsseするで」っていうのを表します。特に難しいことはありません。

                    
yield "data: {0} {1}".format(str(i),"\n\n")
                    
            
これはもちろんレスポンス内容です。

この、data:っていうやつはsseするときにデータを返す時にmessageイベント(後でやる)で受け取れるよってやつです。
とりあえずよくわからなかったらdataつけとけば問題ないです。

あと、文字の後ろに\n\n(改行2つ)を追加していますがsseするときdataの後ろは絶対につけなければいけないので注意してください。


yieldについても一応おさらいしておきます。文字量が多くなるn((
yieldは関数のreturnの進化版みたいなやつでgeneratorと言う型で返してきます。

どういう機能かと言うと、yieldに到達したら実行をやめてこの関数を呼び出している関数に処理を戻すって感じです。
ちなみにflaskで使うとストリーミング通信にできます。


index.html
                    
var es = new EventSource('/sse');

es.addEventListener('message', function (event) {
    console.log(event.data);
});
                    
            
ここら辺はsseするよーって言ってmessageイベントを受け取ってconsole.logにメッセージを表示するよって感じです。
ちなみに「data:」と言うレスポンスはmessegeと言うイベントで受け取れます。

そのほかにも色々なイベントがあるのでドキュメントなどで調べてみてください。