HTTPを介した非同期データ交換

少し前まで、私は仕事で、Java WebアプリケーションとクライアントフロントエンドWebエンドの間の非同期データ交換のメカニズムを実装する仕事をしていました。 タスクは、クライアントが最小遅延で更新を受信することでしたが、更新は毎秒100更新、毎分1更新、つまり クライアントから不要なリクエストを送信しないことをお勧めします。



まず、このリクエストが毎秒生成されたクライアントから送信されたリクエストに即座に応答するテストサーブレットをスケッチしました。 もちろん、このスキームは理想とはほど遠いので、グーグルを始めました。





ところで、これが機能するスキーム:







そして、ここにクライアント側のコードがあります(超自然的なものではありません:タイマー+ JSONリクエストの送信):



function onLoad() { // Invoke request update each second intervalId = setInterval ( requestUpdate(), 1000 ); } function requestUpdate() { $.getJSON(URL, JSONParams, function(data) { $.each(data, function(key, val) { // Process data }) }).success(function(){ // Succes handler }).error(function(){ // Error handler }); }; function onUnload() { clearInterval(intervalID); }; $(document).ready(function() { // Disable caching for ajax $.ajaxSetup({ cache: false }); });
      
      







そして、サーバー側から(倫理的な側面については、アプリケーションのビジネスロジックを担当するコードを明かすことはできませんが、記事の要点はそこにありません):



 public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //Get reqeust parameters JSONObject jsonObj = JSONObject.fromObject(req.getParameterMap()); //Some code //Get writer PrintWriter out = res.getWriter(); //Create json object for response Map<String, String[]> map = retriever.getUpdates(); JSONObject jsonObject = JSONObject.fromObject(map); //Send response out.println(jsonObject); //Finish response! out.close(); }
      
      







最初に出会ったのは、ロングポーリングに関する記事でした(すべてのクライアントが最新のブラウザをインストールできるわけではないため、すぐにWebSocketsを除外しました)。 httpプロトコルを使用してサーバーとクライアント間の非同期データ交換を編成する主なポイントを詳述するIBM Developerworks Webサイトの記事に非常に興味がありました。 この記事では、興味深い例に注目しました。 それに慣れることをお勧めします(もちろん、興味があるなら)。



顧客が使用するTomcatで後に判明したように、omet(Pushing)メカニズムもサポートされています。 CometProcessorインターフェースを実装することで実装されます。 詳細なは、Tomcat Webサイトにあります。そのため、ドキュメントと共に例を参照することをお勧めします。



その結果、このエンジンをサーバー側に実装することにしました。 例とは少し異なります(記事へのリンク)。



長いポーリング接続の作業スキーム:







上記のスキームとの主な違いは、サーバーがすぐに応答を送信するのではなく、特定のイベントを待機することです。 これは、要求ヘッダーにキープアライブタグを設定することで実現されます。 このタグにより、サーバーは時期尚早に切断されません。 応答が送信され、クライアントがそれを受信した後、クライアントは再び別の要求を送信し、応答を待ちます。 基本的に、ここでは再帰呼び出しが行われています。



javascpirtでの長いポーリングクライアントの実装:

 function go(){ var url = "your url" var request = new XMLHttpRequest(); request.open("GET", url, true); request.setRequestHeader("Content-Type","application/x-javascript;"); request.onreadystatechange = function() { if (request.readyState == 4) { if (request.status == 200){ if (request.responseText) { //Something } } go(); } }; request.send(null); }
      
      







そして、jQueryを使用すると次のようになります。

 function poll(){ $.ajax({ url: "your url", success: function(data){ //Something }, dataType: "json", complete: poll, timeout: 30000 }); });
      
      







ストリーム接続の作業スキーム:







ここでわかるように、クライアントは最初に1つのリクエストのみを送信します。 そして、サーバーはイベントごとに情報をクライアントに送信します。 これは、応答のライターが閉じず、送信がflush()メソッドを介してのみ行われるという事実により実現されます。 これにより、クライアントは引き続きストリームから情報を読み取ります。



Javascriptクライアントストリームの実装:

 function switchXHRState() { switch (this.readyState) { case 0: $("#messages").append("open() has not been called yet."); break; case 1: $("#messages").append("send() has not been called yet."); break; case 2:$("#messages").append("send() has been called, headers and status are available."); break; case 3: if (this.status == 200) {Some lines of code} break; case 4: $("#messages").append("Complete!"); break; } }; function go() { var url = "comet"; var request = new XMLHttpRequest(); request.onreadystatechange = switchXHRState; request.open("GET", url, true); request.setRequestHeader("Content-Type", "application/x-javascript;"); request.setRequestHeader("Cache-Control", "no-cache"); request.setRequestHeader("Cache-Control", "no-store"); request.setRequestHeader("Cache-Control", "no-store"); request.send(null); }
      
      







追加資料:

1. プッシュテクノロジーに関するウィキペディアの記事

2.写真が撮影された英語の記事

3. AJAXパターン (名前はそれ自体を物語っています)

4. XMLHttpRequestの仕様






All Articles