サーバー送信イベントを使用したHTTPサーバープッシュの実装

このテーマについてはすでに多くの記事がありますが、すべてからは程遠い真実が明らかにされています。 見逃した方は、 サーバー送信イベントを使用したリアルタイムアプリケーションの作成をご覧ください



Server-Sent-Eventsはどのように機能しますか?



簡単な例:

(new EventSource('/events')).addEventListener('message', function (e) {

document.getElementById('body').innerHTML += e.data + '

';

}, false);






ブラウザはhttp接続を確立し、サーバーからの各メッセージに対してイベントがトリガーされ、そのハンドラーでメッセージテキストを取得できます。 同時に、XMLHTTPRequestが必要とするため、サーバー側から接続を切断する必要はありません。 したがって、接続が確立されると、サーバーからメッセージを受信できます。



Server-sent-eventsのもう1つの利点は、最新の仕様がChrome、Opera 11+ブラウザーでサポートされるようになり、Firefox Auroraでサポートが宣言され、IE8 +、Firefox 3.5+のブラウザーではpolyfillをjavascriptで実装でき、polyfillが使用できることですロングポーリング。 したがって、EventSourceはWebSocketsよりも適切にサポートされます。 (ここでネイティブサポートを探します-http://caniuse.com/#search=eventsource



同時に、親友がサーバー側で動作するためには、ライブラリを接続する必要はありません。標準が要求するように、Server-sent-eventsを使用して作業を実装するだけで十分です(socket.ioで行われているように、各ajaxトランスポートそれを非常に複雑にし、より多くの輸送-より多くの微妙さ)



そのため、IE8はXDomainRequestをサポートしています 。これは、サーバープッシュテクノロジーで動作します。 HTTP接続を中断せずにメッセージを受信することもできます。

残念ながら、XDomainRequestにはパディングが必要です-応答本文の先頭に2キロバイトですが、これは問題ではありません。 また、XDomainRequestは要求ヘッダーの設定をサポートしていないため、 Last-Event-IDを要求本文(POST)で送信する必要があります。



XDomainRequestとその機能の詳細については、こちらをご覧ください-http://blogs.msdn.com/b/ieinternals/archive/2010/04/06/comet-streaming-in-internet-explorer-with-xmlhttprequest-and-xdomainrequest.aspx ?PageIndex = 1



Firefoxブラウザーでは、標準のXMLHttpRequestを介してサーバーからのメッセージを処理できます( javascript.ru/ajax/comet/xmlhttprequest-interactiveの記事を参照)

したがって、サーバープッシュもサポートします。



残りのブラウザーについては、XMLHttpRequestを使用して(つまり、各メッセージの送信後にそのようなブラウザーの接続を切断する必要があるサーバーから)ロングポーリングスキームに従って受信メッセージを整理することができます。

そのため、ネイティブサポートを持たないブラウザーの完成したEventSourceはhttps://github.com/Yaffle/EventSourceです。

ライブラリの依存関係はなく、動作するために必要なものはすべてあります。

<script type="text/javascript" src="eventsource.js"></script>







サーバープッシュとロングポーリングの使用に関する問題



ブラウザーは同時接続の数を制限するため、複数のブラウザータブでサイトを開くときに問題が発生する可能性があります。 もちろん、最新のブラウザーでは、接続数は少なくとも6つに制限されていますが、サイトの各タブで2つ以上のHTTP接続を使用している場合、すぐにこの制限に達します。

SharedWorkerはこの問題を解決するのに最適ですSharedWorkerを作成したら、その中にEventSourceを作成し、すべてのイベントをEventSourceから接続されているすべてのスクリプトに送信できます。



例、sharedworker.js:

var es = new self.EventSource('events'),

history = [];

es.addEventListener('message', function (e) {

history.push(e.data);

}, false);

self.onconnect = function onConnect(event) {

var port = event.ports[0]; //

history.forEach(function (data) {

port.postMessage(data);

});

es.addEventListener('message', function (e) {

port.postMessage(e.data);

}, false);

}







ただし、残念ながら、SharedWorkerはOpera 10.6+およびChrome(Safari)でのみサポートされています。 同時に、Operaには、SharedWorkerの「内部」(つまりSharedWorkerGlobalScope内)にEventSourceオブジェクトがありません。 したがって、複数の接続を回避するこの方法は、Webkitブラウザーにのみ適用できます。 他のすべてのブラウザーの場合、別のドメインを作成する必要があります。 なぜなら EventSourceはクロスドメインリクエストをサポートしていません。EventSourceドメインにあるhtmlページにiframeを介して接続することをお勧めします。これはEventSourceを「トリガー」し、「postMessage」を介してメッセージを送信します(このトピックに関する最近の記事-http:// habrahabr。 com / blogs / javascript / 120336 / 、これはeasyxdmライブラリの使用について説明していますが、「window.postMessage」は最新のブラウザー( http://caniuse.com/#search=postmessage )でかなりよくサポートされています。



最終イベントID



サーバーとの接続が切断されると(サーバーが接続を閉じたか、何らかのネットワークエラーが発生した場合)、EventSourceは一定時間後に再接続します(この時間は制御できます)。 この場合、新しい接続のヘッダーにはLast-Event-ID-最後に受信したメッセージの識別子が含まれます。

サーバー応答の例を考えてみましょう-イベントストリーム:

再試行:1000 \ n

id:123

データ:hello world \ n \ n



` retry`フィールドは、切断の場合に再接続するミリ秒数をサーバーに伝えます。 ` id`フィールドは、再接続時にLast-Event-IDヘッダーで渡されます。 したがって、サーバー側では、ユーザーが最後に受信したメッセージの識別子を簡単に判断し、その後に蓄積されたすべてを転送できます。 ユーザーは、何も失わずにすべてのメッセージを受け取ります。 この例では簡単にするために、メッセージは認証およびCSRFに対する保護なしでGETメソッドを使用して送信されます。 チャット時間はサーバーに対してローカルです、申し訳ありません。



チャットの例: http : //hostel6.ru : 8002



チャットソースは、 https//github.com/Yaffle/EventSourceからダウンロードできます。

ご清聴ありがとうございました!



UPD:IE8 +、FF4-5のCORSサポートを追加



All Articles