Python
Django
Server-Sent-Events

DjangoでServer-Sent Eventsを行う方法

More than 1 year has passed since last update.

DjangoでWebSocketやるには時間が足りないけどサーバーサイドpushをしたかったので、ゴリ押しでSSRを使って対処することにしました
修正点があれば指摘していただけると幸いです

注意

ローカルサーバーで実験した所、接続を中断させた時に[ConnectionAbortedError: [WinError 10053] 確立された接続がホスト コンピューターのソウトウェアによって中止されました。]というエラーメッセージが出ます
恐らく無害だと思いますが、気持ち悪いので扱う時は気をつけて下さい

そもそもServer-Sent Eventsって何よ

ざっくり言うとすごいCometです。つまりゴリ押しサーバーサイドpushみたいなものです
WebSocketの方が優秀かもしれませんが、実装コストが低いのがメリットです
詳しく知りたい方は調べて下さい。

コード内容概要

SSEをするだけ。他のIDなどの機能は一切省く

コード

Python側

ストリーミング配信を行う

views.py
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"

urls.py
    url(r'^stream/$', views.stream_response, name='stream_response'),
    url(r'^stream/template/$', DevSSETemplate.as_view(), name='stream_response_template'),

JavaScript側

取得してリストに加えるだけ

stream.html
<!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のサポートが進んでないフレームワークでは有用であると思われるが、恐らくダサいから何故か流行らないのが不思議です