DjangoでWebSocketやるには時間が足りないけどサーバーサイドpushをしたかったので、ゴリ押しでSSRを使って対処することにしました
修正点があれば指摘していただけると幸いです
注意
ローカルサーバーで実験した所、接続を中断させた時に[ConnectionAbortedError: [WinError 10053] 確立された接続がホスト コンピューターのソウトウェアによって中止されました。]というエラーメッセージが出ます
恐らく無害だと思いますが、気持ち悪いので扱う時は気をつけて下さい
そもそもServer-Sent Eventsって何よ
ざっくり言うとすごいCometです。つまりゴリ押しサーバーサイドpushみたいなものです
WebSocketの方が優秀かもしれませんが、実装コストが低いのがメリットです
詳しく知りたい方は調べて下さい。
コード内容概要
SSEをするだけ。他のIDなどの機能は一切省く
コード
Python側
ストリーミング配信を行う
from django.views.decorators.http import condition
from django.http import StreamingHttpResponse
from django.views.generic import UpdateView, DetailView, FormView, TemplateView, DeleteView
import time
@condition(etag_func=None)
def stream_response(request):
resp = StreamingHttpResponse(stream_response_generator(), content_type='text/event-stream')
return resp
def stream_response_generator():
while(True):
yield "data: %s\n" \
"retry:1000\n\n" % 0
time.sleep(1)
class DevSSETemplate(TemplateView):
template_name = "stream.html"
url(r'^stream/$', views.stream_response, name='stream_response'),
url(r'^stream/template/$', DevSSETemplate.as_view(), name='stream_response_template'),
JavaScript側
取得してリストに加えるだけ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id ="log"></div>
</body>
<script>
window.onload = function() {
var evtSource = new EventSource("{% url 'accounts:stream_response' %}");
var eventList = document.getElementById("log");
evtSource.onmessage = function(e) {
console.log(e);
var newElement = document.createElement("li");
newElement.innerHTML = "message: " + e.data;
eventList.appendChild(newElement);
};
}
</script>
</html>
解説
@.condition(etag_func=None)
ETag(キャッシュ周り)を無効化する?
StreamingHttpResponse
このメソッドを使うとストリーミング配信が出来る。普段はPDFなどを送信する時に使うそうです
これを含め、Djangoには機能なものが多く、痒い所に手が届くのはありがたいです
感想
これで一応動きました
SSEは実装コストが低く、WebSocketのサポートが進んでないフレームワークでは有用であると思われるが、恐らくダサいから何故か流行らないのが不思議です