皆さん、SSE(Server Sent Events)をご存知でしょうか?
Node.jsが有名過ぎて隠れてしまっていますが、双方向通信が必要なく、サーバーからクライアントへ一方向通信するなら、SSEの方が断然簡単です!
今回はそんなSSEをLaravelに導入したいと思います。
SSE導入の目的
例えば、外部APIを利用し、データをリアルタイムに取得して表示したい場合に利用します。
下記の例では、単純な数字をサーバーからクライアントへ送信するサンプルです。
SSEのメリット
HTTPで通信するので通信の互換性が高く、別のソケットを確保したり、サーバー側で特別な設定をする必要がありませんので、レンタルサーバーでも簡単に構築することができ、JavaScriptの知識だけで済むので学習コストが掛かりません。
サンプルコード
Laravelフレームワークを利用する際、SSEをどこに記述しようか、かなりなやみますが、サンプルではとりあえずコントローラにしておきます。
コントローラ(サーバ側)
SSEのレスポンスは、LaravelがベースにしているSymfonyフレームワークのStreamedResponseを使用してクライアント側に返します。
public function sse(Request $request)
{
$response = new StreamedResponse(function() use ($request) {
$requestData = $request->all();
while(true) {
$datas = $requestData;
echo 'data: ' . json_encode($datas) . "nn";
ob_flush();
flush();
sleep(1);
}
});
$response->headers->set('Content-Type', 'text/event-stream');
$response->headers->set('X-Accel-Buffering', 'no');
$response->headers->set('Cache-Control', 'no-cache');
return $response;
}
コントローラ解説
StreamedResponse
のコールバック関数に引数を渡したい場合は、useを使用してください。
ここでは、クライアント側から送信されてくるリクエストパラメータをそのまま渡しています。while(true)
でサーバー側で処理を繰り返します。$datas
に何かしらのデータを配列で格納し、JSON形式でクライアント側に送信します。sleep()
関数に次の処理まで何秒待つかを記述します。
ここでは1秒毎にwhile(true) {...}
内の処理を繰り返し行います。
ビュー(クライアント側)
ビューが表示された際にコントローラで設定した処理を開始するように記述します。
そして、サーバから受信したデータをどうにかこうにかします。
<script>
var datas;
var es = new EventSource("{{ route('sse', ['x' => 1, 'y' => 2]) }}");
es.addEventListener('message', function (e) {
datas = JSON.parse(e.data);
console.log(datas);
// datas.x = 1;
// datas.y = 2;
});
<script>
ビュー解説
new EventSource()
でサーバー側の処理が開始されます。
サンプルでは、['x' => 1, 'y' => 2]
というリクエストパラメータをサーバー側に渡して、同じデータを受信するようにしています。
サーバーから送られてくるJSON形式のデータをパースして、datas
変数に格納しています。
ESSのエラーが発生した場合は以下のように処理を停止することもできます。
es.addEventListener('error', function (e) {
es.close();
});
擬似的にリアルタイムも可能!
勘が良い方はもうお気付きだと思いますが、擬似的に双方向のリアルタイム通信を再現することもできます。
WebRTC(リアルタイムチャット)を例に簡単にご説明します。
要は、while(true) {...}
の処理中にデータベースを参照し、既読フラグが立っていないメッセージを送信するだけです。
つまり、データをどこかに溜めて、双方向通信しているように思わせるわけです。
具体的なコードはまた今度にします。
SSEの可能性
個人的にSSEはもっと活躍できるのではと考えています。
SSEを利用したWebRTCは、いつか本気で実現させようと思っています。
ただ、iOSの場合のみブラウザやデスクトップのプッシュ通知機能がサポートされていないので、今か今かとずっと待っていますが…。
- Original:https://minory.org/laravel-sse.html
- Source:Minory
- Author:管理者