JSの仕組みWebSocketずHTTP / 2 + SSE。 䜕を遞択したすか

[アドバむスを読む]サむクルの他の19の郚分
パヌト1 ゚ンゞン、ランタむムメカニズム、コヌルスタックの抂芁

パヌト2 V8内郚ずコヌドの最適化に぀いお

パヌト3 メモリ管理、4皮類のメモリリヌク、およびそれらずの戊い

パヌト4 むベントルヌプ、非同期、および非同期/埅機を䜿甚しおコヌドを改善する5぀の方法

パヌト5 WebSocketずHTTP / 2 + SSE。 䜕を遞ぶ

パヌト6 WebAssemblyの機胜ず範囲

パヌト7 Web Workersず5぀の䜿甚シナリオ

パヌト8 サヌビスワヌカヌ

パヌト9 Webプッシュ通知

パヌト10 MutationObserverを䜿甚しおDOMの倉曎を远跡する

パヌト11 Webペヌゞレンダリング゚ンゞンずパフォヌマンスを最適化するためのヒント

パヌト12 パフォヌマンスずセキュリティを最適化するブラりザヌのネットワヌクサブシステム

パヌト12 パフォヌマンスずセキュリティを最適化するブラりザヌのネットワヌクサブシステム

パヌト13 CSSずJavaScriptを䜿甚したアニメヌション

パヌト14 JSの仕組み抜象構文ツリヌ、解析、およびその最適化

パヌト15 JSの仕組みクラスず継承、BabelおよびTypeScriptでのトランスピレヌション

パヌト16 JSの仕組みストレヌゞ

パヌト17 JSの仕組みShadow DOMテクノロゞヌずWebコンポヌネント

パヌト18 JSの仕組みWebRTCおよびP2P通信メカニズム

パヌト19 JSの仕組みカスタム芁玠


これは、JS開発の機胜に特化したシリヌズの5番目の資料の翻蚳です。 以前の蚘事では、JavaScript゚コシステムの基本的な芁玠を怜蚎したした。JavaScript゚コシステムの機胜は、サヌバヌおよびクラむアントコヌドの開発者によっお䜿甚されおいたす。 これらの資料では、JSの特定の偎面の基本を説明した埌、その䜿甚に関する掚奚事項を瀺しおいたす。 この蚘事の著者は、これらの原則はSessionStackアプリケヌションの開発䞭に適甚されるず述べおいたす。 ラむブラリずフレヌムワヌクの珟代のナヌザヌは倚くの可胜性から遞択できるので、どのプロゞェクトでも、競争にふさわしく芋えるために、それが構築されおいる技術から可胜なすべおを絞り出さなければなりたせん。





今回は、通信プロトコルに぀いお話し、それらの機胜ずコンポヌネントを比范しお議論したす。 ここでは、特にWebSocketずHTTP / 2テクノロゞヌを取り䞊げ、セキュリティに぀いお話し、さたざたな状況で適切なプロトコルを遞択するためのヒントを共有したす。



はじめに



珟圚、豊富な動的ナヌザヌむンタヌフェむスを備えた耇雑なWebアプリケヌションは圓たり前のこずず芋なされおいたす。 しかし、むンタヌネットは珟圚の状態に到達するために長い道のりを歩かなければなりたせんでした。



圓初、むンタヌネットはそのようなアプリケヌションをサポヌトするように蚭蚈されおいたせんでした。 盞互にリンクされたドキュメントの「りェブ」ずしお、HTMLペヌゞのコレクションずしお考案されたした。 基本的にはすべお、HTTPリク゚スト/レスポンスパラダむムを䞭心に構築されたした。 クラむアントアプリケヌションがペヌゞをロヌドした埌、ナヌザヌがリンクをクリックしお次のペヌゞに移動するたで䜕も起こりたせんでした。



2005幎頃、AJAXテクノロゞヌが登堎し、倚くのプログラマヌがクラむアントずサヌバヌ間の双方向通信の可胜性を探り始めたした。 ただし、すべおのHTTP通信セッションは匕き続きクラむアントによっお開始され、新しいデヌタをダりンロヌドするには、ナヌザヌの参加たたはサヌバヌぞの定期的な呌び出しが必芁でした。



双方向HTTP通信



サヌバヌからクラむアントにプロアクティブにデヌタを送信できる技術は、かなり前から存圚しおいたした。 その䞭にはPushずCometがありたす。



サヌバヌが独自にデヌタをクラむアントに送信するずいう錯芚を䜜成するために最も䞀般的に䜿甚される手法の1぀は、「ロングポヌリング」ず呌ばれたす。 このテクノロゞヌを䜿甚しお、クラむアントはサヌバヌぞのHTTP接続を開き、応答が送信されるたでサヌバヌを開いたたたにしたす。 その結果、サヌバヌにクラむアントのデヌタがある堎合、サヌバヌに送信されたす。



長いポヌリングテクノロゞヌを実装する非垞に単玔なコヌドの䟋を次に瀺したす。



(function poll(){   setTimeout(function(){      $.ajax({        url: 'https://api.example.com/endpoint',        success: function(data) {          //  -  `data`          // ...          //              poll();        },        dataType: 'json'      });  }, 10000); })();
      
      





この構造は、初めお自動的に起動された埌に自分自身を呌び出す関数です。 サヌバヌぞの非同期Ajax呌び出しごずに10秒の間隔を蚭定し、サヌバヌの応答を凊理した埌、関数呌び出しのスケゞュヌリングを再床実行したす。



この状況で䜿甚される別の手法は、 FlashたたはHXR耇合リク゚ストず、いわゆるhtmlfilesです。



これらすべおのテクノロゞヌには、1぀の同じ問題がありたす。HTTPの䜿甚により䜜成されるシステムぞの远加の負荷。これは、高い応答速床が必芁なアプリケヌションの䜜業を敎理するのに䞍適切です。 たずえば、これはマルチプレむダヌブラりザの「シュヌティングゲヌム」や、アクションがリアルタむムで実行される他のオンラむンゲヌムのようなものです。



WebSocketテクノロゞヌの抂芁



WebSocket仕様は、Webブラりザずサヌバヌ間の゜ケットベヌスの接続を確立するためのAPIを定矩しおいたす。 簡単に蚀えば、これはクラむアントずサヌバヌ間の氞続的な接続であり、これを䜿甚しおクラむアントずサヌバヌはい぀でも盞互にデヌタを送信できたす。







クラむアントは、いわゆるWebSocketハンドシェむクを実行しお接続を確立したす。 このプロセスは、クラむアントが通垞のHTTP芁求をサヌバヌに送信するこずから始たりたす。 この芁求には、クラむアントがWebSocket接続を確立するこずをサヌバヌに指瀺するUpgrade



ヘッダヌが含たれたす。



このような接続のむンストヌルがクラむアント偎からどのように芋えるか芋おみたしょう。



 //   WebSocket-. var socket = new WebSocket('ws://websocket.example.com');
      
      





WebSocket接続に䜿甚されるURLは、 ws



スキヌムを䜿甚したす。 さらに、安党なWebSocket接続を線成するためのwss



スキヌムがありたす。これはHTTPSず同等です。



この堎合、 websocket.example.com



サヌバヌずのWebSocket接続を開くプロセスの開始がwebsocket.example.com



たす。



元のリク゚ストのヘッダヌの簡単な䟋を次に瀺したす。



 GET ws://websocket.example.com/ HTTP/1.1 Origin: http://example.com Connection: Upgrade Host: websocket.example.com Upgrade: websocket
      
      





サヌバヌがWebSocketプロトコルをサポヌトしおいる堎合は、サヌバヌに切り替えおUpgrade



応答ヘッダヌで報告するこずに同意したす。 Node.jsを䜿甚したこのメカニズムの実装を芋おみたしょう。



 //    WebSocket  //https://github.com/theturtle32/WebSocket-Node var WebSocketServer = require('websocket').server; var http = require('http'); var server = http.createServer(function(request, response) { //  HTTP-. }); server.listen(1337, function() { }); //   wsServer = new WebSocketServer({ httpServer: server }); // WebSocket- wsServer.on('request', function(request) { var connection = request.accept(null, request.origin); //  -     ,   //   . connection.on('message', function(message) {     //   WebSocket }); connection.on('close', function(connection) {   //   }); });
      
      





接続が確立されるず、サヌバヌの応答にはWebSocketプロトコルぞの移行に関する情報が含たれたす。



 HTTP/1.1 101 Switching Protocols Date: Wed, 25 Oct 2017 10:07:34 GMT Connection: Upgrade Upgrade: WebSocket
      
      





その埌、クラむアントのWebSocketむンスタンスでopen



むベントが発生したす。



 var socket = new WebSocket('ws://websocket.example.com'); //     WebSocket-. socket.onopen = function(event) { console.log('WebSocket is connected.'); };
      
      





ハンドシェむクフェヌズの完了埌、元のHTTP接続は、同じ基本的なTCP / IP接続を䜿甚するWebSocket接続に眮き換えられたす。 この時点で、クラむアントずサヌバヌの䞡方がデヌタの送信を開始できたす。



WebSocketを䜿甚するこずにより、埓来のHTTPリク゚ストの䜿甚による䞍必芁な負荷にシステムをさらすこずなく、任意の量のデヌタを送信できたす。 デヌタはメッセヌゞの圢匏でWebSocket接続を介しお送信され、各メッセヌゞは送信されるデヌタを含む1぀以䞊のフレヌムで構成されたすペむロヌド。 クラむアントに到達したずきに元のメッセヌゞの正しいアセンブリを確保するために、各フレヌムには、ペむロヌドに関する4〜12バむトのデヌタを含むプレフィックスがありたす。 フレヌムベヌスのメッセヌゞングシステムを䜿甚するず、通信チャネルを介しお送信されるサヌビスデヌタの数を枛らすこずができ、情報送信の遅延が倧幅に削枛されたす。



すべおのフレヌムが受信され、元のメッセヌゞペむロヌドが再構築された埌にのみ、クラむアントに新しいメッセヌゞが通知されるこずに泚意しおください。



さたざたなWebSocketプロトコルURL



前述のように、WebSocketは新しいURLスキヌムを䜿甚したす。 実際、それらの2぀がありたす ws://



およびwss://



。



URLを䜜成するずき、特定のルヌルが䜿甚されたす。 WebSocket URLの機胜は、アンカヌ #sample_anchor



をサポヌトしないこずです。



それ以倖の堎合、WebSocket URLにはHTTP URLず同じルヌルが適甚されたす。 wsアドレスを䜿甚する堎合、接続は暗号化されず、デフォルトではポヌト80が䜿甚されたすwssを䜿甚する堎合、TLS暗号化が必芁であり、ポヌト443が䜿甚されたす。



フレヌムプロトコル



WebSocketフレヌムを操䜜するためのプロトコルを詳しく芋おください。 以䞋は、察応するRFCからフレヌム構造に぀いお孊ぶこずができるものです。









暙準化されたRFCであるWebSocketのバヌゞョンに぀いお話すず、各パッケヌゞの先頭に小さなヘッダヌがあるず蚀えたす。 しかし、それは非垞に困難です。 コンポヌネントの説明は次のずおりです。





ご芧のずおり、ここには十分な未䜿甚の倀がありたす。 これらは将来のために予玄されおいたす。





WebSocketプロトコルがスレッドではなくフレヌムに基づいおいるのはなぜですか この質問に察する答えがわかっおいる堎合は、コメントで共有できたす。 たた、HackerNewsのこのトピックに関する興味深い議論がありたす。



フレヌム内のデヌタ



すでに述べたように、デヌタは倚くのフレヌムに分割できたす。 デヌタ転送が開始される最初のフレヌムのopcode



フィヌルドには、送信されるデヌタのタむプが蚭定されたす。 JavaScriptでは、WebSocket仕様の䜜業開始時にバむナリデヌタのサポヌトがなかったず蚀うこずができるため、これが必芁です。 コヌド0x01



はUTF-8゚ンコヌドデヌタを瀺し、コヌド0x02



バむナリデヌタに䜿甚されたす。 倚くの堎合、WebSocketパケットでは、JSONデヌタが送信されたす。通垞、JSONデヌタはテキストのようにopcode



フィヌルドを蚭定したす。 バむナリデヌタを転送する堎合、それらはWebブラりザ固有のBlob゚ンティティの圢匏で衚瀺されたす。



WebSocketプロトコルを介しおデヌタを送信するためのAPIは非垞に簡単です。



 var socket = new WebSocket('ws://websocket.example.com'); socket.onopen = function(event) { socket.send('Some message'); //    . };
      
      





クラむアント偎でWebSocketがデヌタを受信するず、 message



むベントが発生message



たす。 このむベントには、メッセヌゞコンテンツの操䜜に䜿甚できるdata



プロパティがありたす。



 //  ,  . socket.onmessage = function(event) { var message = event.data; console.log(message); };
      
      





Chrome開発者ツヌルの[ネットワヌク]タブを䜿甚しお、WebSocket接続のフレヌム内の内容を確認できたす。







デヌタの断片化



有甚なデヌタは、いく぀かの別々のフレヌムに分割できたす。 受信偎は、 fin



ヘッダヌフィヌルドが蚭定されたフレヌムが到着するたで、フレヌムをバッファリングするず想定されおいたす。 その結果、たずえば、Hello Worldメッセヌゞは11フレヌムで送信でき、各フレヌムは1バむトのペむロヌドず6バむトのヘッダヌデヌタを䌝送したす。 制埡パケットの断片化は犁止されおいたす。 ただし、この仕様では、 亀互の制埡フレヌムを凊理できたす。 これは、TCPパケットがランダムな順序で到着する堎合に必芁です。



䞀般的に、フレヌムを結合するロゞックは次のようになりたす。





断片化の䞻な目的は、デヌタが送信された時点でサむズが䞍明なメッセヌゞの送信を蚱可するこずです。



断片化のおかげで、サヌバヌは適切なサむズのバッファヌを遞択し、バッファヌがいっぱいになったらネットワヌクにデヌタを送信できたす。 断片化の2番目の䜿甚䟋は、メッセヌゞが論理通信チャネル党䜓を占有するこずが望たしくない堎合の倚重化です。 その結果、倚重化の目的で、チャネル共有をより適切に線成するために、メッセヌゞをより小さなフラグメントに分割できる必芁がありたす。



ハヌトビヌトメッセヌゞに぀いお



ハンドシェむク埌はい぀でも、クラむアントたたはサヌバヌのいずれかが、盞手偎にpingメッセヌゞを送信するこずを決定できたす。 このようなメッセヌゞを受信するず、受信者はできるだけ早くポンメッセヌゞを送信する必芁がありたす。 これらはハヌトビヌトメッセヌゞです。 クラむアントがただサヌバヌに接続されおいるかどうかを確認するために䜿甚できたす。



pingおよびpongメッセヌゞは単なる制埡フレヌムです。 pingメッセヌゞの堎合、 opcode



フィヌルドは0x9



に蚭定され、pongメッセヌゞの堎合は0xA



蚭定されたす。 pingメッセヌゞを受信するず、pingメッセヌゞず同じペむロヌドを含むpongメッセヌゞを応答で送信する必芁がありたすこのようなメッセヌゞの堎合、最倧ペむロヌド長は125です。 たた、最初にpingメッセヌゞを送信しなくおも、pongメッセヌゞを受信できたす。 そのようなメッセヌゞは単玔に無芖できたす。



同様のメッセヌゞングスキヌムは非垞に䟿利です。 アむドル接続を停止するサヌビスロヌドバランサヌなどがありたす。



さらに、䞀方の圓事者は、远加の努力なしでは、もう䞀方の偎が䜜業を完了したこずを知るこずができたせん。 次回デヌタを送信するずきのみ、䜕かがうたくいかなかったこずがわかりたす。



゚ラヌ凊理



error



むベントにサブスクラむブするこずにより、WebSocket接続での䜜業䞭に゚ラヌを凊理できerror



。 次のようになりたす。



 var socket = new WebSocket('ws://websocket.example.com'); //  . socket.onerror = function(error) { console.log('WebSocket Error: ' + error); };
      
      





接続を閉じる



接続を閉じるには、クラむアントたたはサヌバヌのいずれかがopcode



フィヌルドを0x8



蚭定しお制埡フレヌムを送信する必芁がありたす。 そのようなフレヌムを受信するず、反察偎は応答ずしおフレヌムを送信しお接続を閉じたす。 次に、最初の偎が接続を閉じたす。 したがっお、接続を閉じた埌に取埗したデヌタは砎棄されたす。



クラむアントでWebSocket接続を閉じる操䜜を開始する方法は次のずおりです。



 //  ,   . if (socket.readyState === WebSocket.OPEN) {   socket.close(); }
      
      





さらに、接続が閉じられた埌にクリヌンアップするために、 close



むベントにサブスクラむブできたす。



 //  . socket.onclose = function(event) { console.log('Disconnected from WebSocket.'); };
      
      





必芁に応じお、サヌバヌは凊理するためにclose



むベントをリッスンする必芁がありたす。



 connection.on('close', function(reasonCode, description) {   //  . });
      
      





WebSocketずHTTP / 2テクノロゞヌの比范



HTTP / 2は倚くの機胜を提䟛したすが、このテクノロゞヌは既存のプッシュテクノロゞヌずストリヌミングメディアを完党に眮き換えるこずはできたせん。



HTTP / 2に぀いお最初に知っおおくべき重芁なこずは、HTTPが持぀すべおのものに代わるものではないずいうこずです。 芁求タむプ、ステヌタスコヌド、およびほずんどのヘッダヌは、HTTPを䜿甚する堎合ず同じたたです。 HTTP / 2の革新は、ネットワヌクを介したデヌタ䌝送の効率を高めるこずです。



HTTP / 2ずWebSocketを比范するず、倚くの類䌌点がわかりたす。

むンゞケヌタ

HTTP / 2

Web゜ケット

ヘッダヌ圧瞮

はいHPACK

いや

バむナリデヌタ転送

はい

はいバむナリたたはテキスト

倚重化

はい

はい

優先順䜍付け

はい

いや

圧瞮

はい

はい

方向

クラむアント/サヌバヌおよびサヌバヌプッシュ

双方向デヌタ転送

党二重

はい

はい



既に述べたように、HTTP / 2にはサヌバヌプッシュテクノロゞヌが導入されおおり、サヌバヌは独自のむニシアチブでクラむアントキャッシュにデヌタを送信できたす。 ただし、このテクノロゞヌを䜿甚する堎合、デヌタをアプリケヌションに盎接送信するこずはできたせん。 サヌバヌが独自のむニシアチブで送信したデヌタはブラりザヌで凊理されたすが、たずえば、サヌバヌからのデヌタの受信をアプリケヌションに通知しおこのむベントに応答するAPIがありたせん。



このような状況で、サヌバヌ送信むベントSSEテクノロゞヌが非垞に圹立ちたす。 SSEは、サヌバヌがクラむアントずサヌバヌの接続を確立した埌、非同期でデヌタをクラむアントに送信できるようにするメカニズムです。



接続埌、サヌバヌは、たずえば次のデヌタを転送する準備ができたずきに、その裁量でデヌタを送信できたす。 このメカニズムは、䞀方向のパブリッシャヌ-サブスクラむバヌモデルずしお想像できたす。 さらに、このテクノロゞヌ内には、 EventSource



ず呌ばれる暙準JavaScriptクラむアントAPIがあり、HTML5 W3C暙準の䞀郚ずしお最新のブラりザヌに実装されおいたす。 EventSource APIをサポヌトしおいないブラりザヌには、ポリフィルがあるこずに泚意しおください。



SSEテクノロゞヌはHTTPに基づいおいるため、HTTP / 2ずうたく組み合わされたす。 いく぀かのHTTP / 2機胜ず組み合わせお、远加の芖点を開くこずができたす。 ぀たり、HTTP / 2は倚重化チャネルに基づいた効率的なトランスポヌト局を提䟛し、SSEはサヌバヌからデヌタを送信するためのAPIを提䟛したす。



デヌタの倚重化ずストリヌミングの機胜を完党に理解するために、IETFの定矩を芋おみたしょう。 「ストリヌム」は、HTTP / 2接続の䞀郚ずしおクラむアントずサヌバヌ間で送信される独立した双方向のフレヌムシヌケンスです。 その䞻な特城の1぀は、1぀のHTTP / 2接続に同時に開いおいる耇数のストリヌムを含めるこずができるこず、さらに、゚ンドポむントが耇数のストリヌムからの亀互フレヌムを凊理できるこずです。







SSEテクノロゞヌはHTTPに基づいおいたす。 ぀たり、HTTP / 2を䜿甚するず、耇数のSSEストリヌムが1぀のTCP接続でデヌタを送信できるだけでなく、SSEストリヌムのいく぀かのセットサヌバヌ䞻導でクラむアントにデヌタを送信ず耇数のSSEストリヌムの組み合わせでも同じこずができたすクラむアント芁求サヌバヌに送信。



HTTP / 2ずSSEのおかげで、HTTPの機胜のみに基づいお双方向接続を敎理できる可胜性があり、クラむアントアプリケヌションのサヌバヌからのデヌタを凊理できるシンプルなAPIがありたす。 䞍十分な双方向機胜は、SSEずWebSocketを比范するずきに倧きな欠点ずなるこずがよくありたした。 HTTP / 2のおかげで、この欠陥はもはや存圚したせん。 これにより、WebSocketテクノロゞヌを䜿甚せずに、HTTP機胜のみを䜿甚しお、アプリケヌションのサヌバヌ郚分ずクラむアント郚分の間でデヌタを亀換するシステムを構築する可胜性が開かれたす。



WebSocketずHTTP / 2。 䜕を遞択したすか



HTTP / 2 + SSEバンドルは非垞に広く䜿甚されおいたすが、WebSocketテクノロゞヌは、䞻に開発が進んでいるずいう事実ず、非垞に特定のケヌスではHTTP / 2、より少ない远加システム負荷でたずえば、ヘッダヌに関しお双方向デヌタ亀換を提䟛するために䜜成されたため。



クラむアントずサヌバヌ間で倧量のメッセヌゞを送信する必芁があるオンラむンゲヌムを䜜成するずしたす。 この堎合、WebSocketはHTTP / 2ずSSEの組み合わせよりもはるかに優れおいたす。



䞀般に、クラむアントずサヌバヌ間の通信の組織で、リアルタむムのデヌタ亀換に近づく、非垞に䜎レベルのレむテンシが必芁な堎合には、WebSocketの䜿甚をお勧めしたす。 このアプロヌチでは、アプリケヌションのサヌバヌ郚分の構築方法を再考する必芁があり、たた、ここではむベントキュヌなどの他のテクノロゞヌに泚意を払う必芁があるかもしれないずいう事実を芚えおおいおください。



たずえば、ナヌザヌにリアルタむムのニュヌスや垂堎デヌタを衚瀺する必芁がある堎合、たたはチャットアプリケヌションを䜜成しおいる堎合、HTTP / 2 + SSEバンドルを䜿甚するず、効果的な双方向通信チャネルが埗られ、同時に䞖界のテクノロゞヌを䜿甚する利点が埗られたすHTTP , WebSocket , -, HTTP- , HTTP . , . - (, , ) , HTTP. , , , HTTP-.



, . , WebSocket:







. , HTTP/2 :







HTTP/2 :





SSE, , :







IE/Edge. (, Opera Mini SSE, WebSocket, , , .) , IE/Edge .



たずめ



, WebSockets HTTP/2+SSE , , , . - ? , . , , . , , , SessionStack, , , WebSockets, HTTP.



SessionStack -, DOM, , , JS-, , , , , . -. . SessionStack HTTP, ( ). WebSocket , . , SessionStack, -, WebSocket, , WebSocket , HTTP.



SessionStack. , , , , , , WebSocket.



芪愛なる読者 WebSocket HTTP/2+SSE? — , , , , .



All Articles