【python】FlaskでSSE(Server-Sent Events)を実装する
こんばんは
今回はたまたまSSEを実装する機会があったのでそれと同時に
メモ的な感じで書いていきたいと思います。あとflaskのSSEの記事が少ないように感じたので
てなわけでどうぞ
SSEってなんぞや
ってところから始まりますが、飛ばしてもいいです。とばしたいならとばせ
まあ簡単にいうと、webサーバーからリアルタイムでレスポンスを受け取ることができる何ともexcitingな機能です。
実装もそれなりに簡単で、longpollingよりも効率がいいのでこれにしました。
まあwebsocketっていうやつもあるんだけど難しいので後回しにした
プログラミングって難しいよね
ちなみにlongpollingとwebsocketもおさらいしておきましょうかね。文章が多くなってSEO対策になr(((
- longpolling
1.クライアント側からサーバーにリクエストを送る
2.なんかサーバー側の変更があったらレスポンスする
メリット
実装がくそ簡単。
デメリット
http通信のヘッダーとかを省かないで通信してるからサーバーの負荷がやばい。
他の通信よりリアルタイム性がない

- websocket
サーバーがデータをクライアントに送りたいときに送れる。
クライアントもサーバーにデータを送りたいときに送れる
メリット
tcp通信で行うので無駄がなくサーバーに負荷がかからない
デメリット
実装が複雑

じゃあ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と言うイベントで受け取れます。
そのほかにも色々なイベントがあるのでドキュメントなどで調べてみてください。