この記事では、30 分ですぐにマスターできる逆 Ajax に関する関連情報を主に紹介します。必要な友人は参照してください。
シナリオ 1: 新しいメールがあると、Web ページにプロンプト メッセージが自動的に表示されます。ユーザーは受信トレイを手動で更新する必要があります。
シナリオ 2: ユーザーの携帯電話がページ上の QR コードをスキャンすると、ページが自動的にジャンプします。
シナリオ 3: チャット ルームのような環境で誰かが話すと、ログインしているすべてのユーザーがすぐにメッセージを見ることができます。
リクエストをクライアントから開始してサーバーが応答する必要がある従来の MVC モデルと比較して、リバース Ajax を使用すると、サーバーがイベントをクライアントにアクティブにプッシュすることをシミュレートして、ユーザー エクスペリエンスを向上させることができます。この記事では、Comet と WebSocket を含むリバース Ajax テクノロジについて 2 つのパートで説明します。この記事は、上記の 2 つの技術的手段を実装する方法を説明することを目的としており、Struts2 または SpringMVC でのアプリケーションはカバーされていません。また、サーブレットの設定でもアノテーションを使用します。関連する知識については、他の資料を参照してください。
1. Comet (最良の互換性メソッド)
Comet は基本的に、サーバーからクライアントにデータを送信できるという概念です。標準の HTTP Ajax リクエストでは、サーバーができるだけ早くイベントをクライアントに送信できるように、リバース Ajax は何らかの特定の方法で Ajax リクエストの作成をシミュレートします。通常の HTTP リクエストにはページ ジャンプが伴うことが多く、プッシュ イベントではブラウザが同じページまたはフレームにとどまる必要があるため、Comet の実装は Ajax を介してのみ完了できます。
実装プロセスは次のとおりです。ページがロードされると、Ajax リクエストがサーバーに送信され、サーバーはリクエストを取得してスレッドセーフなコンテナー (通常はキュー) に保存します。同時に、サーバーは他のリクエストにも通常どおり応答できます。プッシュする必要があるイベントが到着すると、サーバーはコンテナ内のリクエストを走査し、レスポンスを返した後にイベントを削除します。その後、ページに滞在しているすべてのブラウザが応答を取得し、再度 Ajax リクエストを送信し、上記のプロセスを繰り返します。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html lang="en"> <base href="<%=basePath%>"> <head> <title>WebSocket</title> <script type="text/javascript" src="static/jquery-1.9.1.min.js"></script> <script type="text/javascript"> $(function() { connect(); $("#btn").click(function() { var value = $("#message").val(); $.ajax({ url : "longpolling?method=onMessage&msg=" + value, cache : false, dataType : "text", success : function(data) { } }); }); }); function connect() { $.ajax({ url : "longpolling?method=onOpen", cache : false, dataType : "text", success : function(data) { connect(); alert(data); } }); } </script> </head> <body> <h1>LongPolling</h1> <input type="text" id="message" /> <input type="button" id="btn" value="发送" /> </body> </html>
btn によって送信されたリクエストは、実際には応答を受け取る必要がないことに気付きました。プロセス全体の鍵は、クライアントが常にサーバーの connect() リクエストを維持することです。幸いなことに、これまでのところ、ほとんどのサーブレット コンテナは適切なサポートを提供しています。以下に Tomcat を例に挙げます。
package servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(value="/longpolling", asyncSupported=true) public class Comet extends HttpServlet { private static final Queue<AsyncContext> CONNECTIONS = new ConcurrentLinkedQueue<AsyncContext>(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getParameter("method"); if (method.equals("onOpen")) { onOpen(req, resp); } else if (method.equals("onMessage")) { onMessage(req, resp); } } private void onOpen(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { AsyncContext context = req.startAsync(); context.setTimeout(0); CONNECTIONS.offer(context); } private void onMessage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String msg = req.getParameter("msg"); broadcast(msg); } private synchronized void broadcast(String msg) { for (AsyncContext context : CONNECTIONS) { HttpServletResponse response = (HttpServletResponse) context.getResponse(); try { PrintWriter out = response.getWriter(); out.print(msg); out.flush(); out.close(); context.complete(); CONNECTIONS.remove(context); } catch (IOException e) { e.printStackTrace(); } } } }
ConcurrentLinkedQueue は Queue キューのスレッドセーフ実装であり、ここではリクエストを保存するコンテナとして使用されます。 AsyncContext は Tomcat によってサポートされる非同期環境であり、サーバーごとに使用するオブジェクトが若干異なります。 Jetty でサポートされているオブジェクトは Continuation です。ブロードキャストを完了したリクエストは、context.complete() を通じて関連するリクエストを終了し、CONNECTIONS.remove(context) を使用してキューを削除する必要があります。
2. WebSocket (HTML5 からのサポート)
HTTP ロングポーリングを使用する Comet は、現在すべてのブラウザーがリバース Ajax のサポートを提供しているため、リバース Ajax を確実に実装する最良の方法です。
WebSocket は HTML5 で登場し、Comet よりも新しいリバース Ajax テクノロジーです。 WebSocket は双方向の全二重通信チャネルをサポートしており、多くのブラウザ (Firefox、Google Chrome、Safari) もそれをサポートしています。接続は、HTTP リクエスト (WebSocket ハンドシェイクとも呼ばれる) およびいくつかの特別なヘッダーを通じて行われます。接続は常にアクティブであり、生の TCP ソケットと同じように JavaScript でデータの書き込みと受信を行うことができます。
ws:// または wss:// (SSL 上) を入力して WebSocket URL を開始します。図に示すように:
まず第一に、WebSocket はすべてのブラウザーで十分にサポートされているわけではなく、明らかに IE がサポートを妨げています。したがって、このテクノロジーの使用を計画する場合は、ユーザーの使用環境を考慮する必要があります。プロジェクトがインターネット向けである場合、または携帯電話ユーザーが含まれる場合は、よく考えてみることをお勧めします。
2 番目: WebSocket によって提供されるリクエストは通常の HTTP リクエストとは異なり、全二重通信であり、(オフにしない限り) 常にアクティブになります。これは、応答を受け取るたびにサーバーにリクエストを再度送信する必要がないことを意味し、多くのリソースを節約できます。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; String ws = "ws://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html lang="en"> <base href="<%=basePath%>"> <head> <title>WebSocket</title> <script type="text/javascript" src="static/jquery-1.9.1.min.js"></script> <script type="text/javascript"> $(function() { var websocket = null; if ("WebSocket" in window){ websocket = new WebSocket("<%=ws%>websocket"); } else { alert("not support"); } websocket.onopen = function(evt) { } websocket.onmessage = function(evt) { alert(evt.data); } websocket.onclose = function(evt) { } $("#btn").click(function() { var text = $("#message").val(); websocket.send(text); }); }); </script> </head> <body> <h1>WebSocket</h1> <input type="text" id="message" /> <input type="button" id="btn" value="发送"/> </body> </html>
JQuery はまだ WebSocket に対するより良いサポートを提供していないため、コードの一部を記述するには Javascript を使用する必要があります (幸いなことに、複雑ではありません)。また、Tomcat を例に挙げると、一部の一般的なサーバーは ws リクエストをサポートできます。バージョン 6.0 では、WebSocketServlet オブジェクトは @java.lang.Deprecated としてマークされています。7.0 以降のバージョンでは、jsr365 によって提供される実装がサポートされるため、関連する構成を完了するにはアノテーションを使用する必要があります。
package servlet; import java.io.IOException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket") public class WebSocket { private static final Queue<WebSocket> CONNECTIONS = new ConcurrentLinkedQueue<WebSocket>(); private Session session; @OnOpen public void onOpen(Session session) { this.session = session; CONNECTIONS.offer(this); } @OnMessage public void onMessage(String message) { broadcast(message); } @OnClose public void onClose() { CONNECTIONS.remove(this); } private synchronized void broadcast(String msg) { for (WebSocket point : CONNECTIONS) { try { point.session.getBasicRemote().sendText(msg); } catch (IOException e) { CONNECTIONS.remove(point); try { point.session.close(); } catch (IOException e1) { } } } } }
3. まとめ(リクエストからプッシュまで)
従来の通信スキームでは、システム A がシステム B からの情報を必要とする場合、システム B にリクエストを送信します。システム B は要求を処理し、システム A は応答を待ちます。処理が完了すると、応答がシステム A に返されます。同期通信モードでは、応答を待つために処理時間が無駄になるため、リソースの使用効率が低くなります。
非同期モードでは、システム A はシステム B から取得したい情報をサブスクライブします。その後、システム A はシステム B に通知を送信するか、情報をすぐに返すことができ、その間にシステム A は他のトランザクションを処理できます。このステップはオプションです。イベント駆動型アプリケーションでは、通常、イベントが何であるかわからないため、他のシステムにイベントの送信を依頼する必要はありません。システム A は、システム B が応答を公開した直後に応答を受信します。
Web フレームワークは従来の「リクエスト - レスポンス」モデルに依存していたため、ページが更新されました。 Ajax、Reverse Ajax、および WebSocket の出現により、イベント駆動型アーキテクチャの概念を Web に簡単に適用できるようになり、分離、スケーラビリティ、および反応性の利点が得られます。ユーザーエクスペリエンスの向上は、新たなビジネスチャンスももたらします。
上記は私があなたのためにまとめたものです。
関連記事:
Ajaxリクエストが成功した後に新しいウィンドウアドレスを開く
以上が30 分でリバース Ajax をマスターするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。