HTTP Push技術でのイベント型のデータ共有　～HTTP1/1 transfer-encoding chunkedとHTTP/2

## はじめに

Web系の技術情報でたまに見かけてた「push技術」という言葉がずっと気になっていて、ふとしたきっかけで調べたので覚書。
単語は知らないけど、実は仕組みは知ってたってよくある話ですよね。

## その前に: よくある2者間のデータ共有方法

どの分野の話でも、更新されていくデータの共有方法については、ざっくりと2種類方法があります。

1. ポーリング型～情報が欲しい側が定期的に情報収集する方法。図はとあるHTTPでの例
<img width="800" alt="ポーリング" src="https://camo.qiitausercontent.com/8a4bee626be328fcb705e60210671634e5ed42d0/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3134383134362f62343337393661662d316532362d396266302d326664372d6536323732313761393261362e706e67">
1. イベント型～情報提供者に都度通知してもらう方法。図はとあるHTTPでの例
<img width="800" alt="イベント" src="https://camo.qiitausercontent.com/06ac02e94325c4ae88942c57b52c6f85b013aea1/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3134383134362f33656535343161342d646532382d646165352d336330302d3662643763656361653962622e706e67">


ポーリング型は情報取得側で何とか出来るので考えることが少なくていい半面、更新のリアルタイム性が低くなります。
そのため、リアルタイム性の高いイベント型のデータ共有方法があるのは

図は以下記事のものを参照させていただきました。実際のクライアントサイド実装方法が記載してある良記事でしたので、Webクライアントサイドの参考にいいと思います。
[リアルタイムなwebアプリを実現する方法(ポーリング、Comet、Server Sent Events、WebSocket)
](https://qiita.com/kimullaa/items/d49bd603be17b36f7495)

ハードに近い層の方が使う言葉だと、イベント型は割り込みと呼んだりもしますね。

## HTTPでのイベント型実現方法

HTTPだと[Push技術あるいはserver push](https://ja.wikipedia.org/wiki/Push%E6%8A%80%E8%A1%93)という呼び名で扱われています。
HTTP 1/1, HTTP/2ともに**同じTCPセッション上で都度response dataを投げる**形になります。上で書いたイベント型の図のままですね。

### HTTP 1/1はTransfer-Encoding: chunked

HTTP 1/1の場合は[Transfer-Encoding: chunked](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Transfer-Encoding#Examples)を利用したHTTP responseを使う方法があります。通常はresponseヘッダーに*Content-Length*が付くんですが、その代わりに*Transfer-Encoding: chunked*を指定します。

```HTTPヘッダー
HTTP/1.1 200 OK 
Content-Type: text/plain 
Transfer-Encoding: chunked <-Content-Lengthを指定せず、代わりにこれを指定
```

*Transfer-Encoding: chunked*を付けた場合にどうやってデータ長を知るかというと、先頭に*長さ\r\n*を付けるだけです
(大体サーバーHW/OSSやブラウザで勝手に対処してくれるので、*Transfer-Encoding: chunked*だけつけておけばOKってケースが多いと思います)

```HTTPボディ
7\r\n
Mozilla\r\n 
```

最後は0\r\n\r\nを付けて終わり。

```HTTPボディ最後
7\r\n
Network\r\n
0\r\n
\r\n
```

こちらの方法を使い、最初のresponseでヘッダーだけ返して、後は変更がある度にchunkedで通知するといった表現が可能になります。
他にもon HTTPの映像配信のように定期的にデータを送信し続ける仕組みや、大きい過ぎてresponse作成に時間のかかるデータを分割したりなんてのにも使えます。

似たような技術でmultipart/form-dataを使った方法も見たことあります。こちらはHTTPボディの中に複数のHTTP responseヘッダー＋ボディを詰めた感じです。

### HTTP/2でのデータ共有方法

HTTP 1/1では1 HTTP requestに対して1 HTTP responseが基本だったため、1 responseを分割するchunked形式が活躍していました。
それに対してHTTP/2ではより高速・効率的な通信を行う為の方法が提供されています。
(実践比較してないので仕様上の話しかできなくてすいません。。)

### HTTP/2ではstreamを使って複数データ送受信が可能

一方HTTP/2では接続が確立した通信の上でstreamというものを作って、stream単位でrequest/responseを扱います。なのでchunkedでやりたかったことがstream上で普通に扱えるので便利ですね。chunkedの代わりにフレームという単位でデータを扱っている感じですね。

[HTTP/2ストリーム、メッセージ、フレーム](https://developers.google.com/web/fundamentals/performance/http2/?hl=ja#_3)より図を抜粋です。
<img width="800" alt="HTTP/2ストリーム、メッセージ、フレーム" src="https://developers.google.com/web/fundamentals/performance/http2/images/streams_messages_frames01.svg?hl=ja">

#### HTTP/2 サーバープッシュ

HTTP/2が提供する新機能の中にサーバープッシュという名称の機能があります。
これはざっくりいうと「扱うことが分かっているリソースをサーバーから送信してあげる」って感じなので、イベントとは少し違いますね。ただサーバー契機での送信になるので合わせて記載しておきます。

<img width="800" alt="HTTP/2ストリーム、メッセージ、フレーム" src="https://developers.google.com/web/fundamentals/performance/http2/images/push01.svg">

## 参考

実装の参考:[リアルタイムなwebアプリを実現する方法(ポーリング、Comet、Server Sent Events、WebSocket)](https://qiita.com/kimullaa/items/d49bd603be17b36f7495)
[MDN Web Doc/Transfer-Encoding](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Transfer-Encoding#Examples)
[HTTP/2の概要](https://developers.google.com/web/fundamentals/performance/http2/)