Home>

Scenario 1:When there is a new email,The web page automatically pops up a prompt message without the user having to manually refresh the inbox.

Scenario 2:After the user's mobile phone scans the QR code on the page,The page will automatically jump.

Scenario 3:Anyone speaking in a chat room-like environment,All logged in users can see the information instantly.

Compared with the traditional MVC model request, which must be initiated from the client and responded by the server,Using reverse ajax can simulate server-side active push events to the client to improve user experience.This article will discuss reverse ajax technology in two parts, including:comet and websocket. The article aims to demonstrate how to implement the above two technical means,The application in struts2 or springmvc is not involved.In addition, the servlet configuration is also annotated.You can refer to other materials for related knowledge.

First, comet (the best compatible method)

Comet is essentially a concept:the ability to send data from the server to the client.In a standard http ajax request, the data is sent to the server,Reverse ajax simulates making an ajax request in some specific way, so that,The server can send events to the client as fast as possible.Since ordinary http requests are often accompanied by page jumps,For push events, the browser needs to stay on the same page or frame.So the implementation of comet can only be done through ajax.

The implementation process is as follows:when the page loads, it sends an ajax request to the server, and the server gets the request and saves it in a thread-safe container (usually a queue). At the same time, the server can still respond to other requests normally.When the event that needs to be pushed comes,The server iterates through the requests in the container and deletes them after returning a response.Then all browsers staying on the page will get the response,And send the ajax request again, repeating the above process.

<%@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" />
<input type="button" value="send" />
</body>
</html>

We have noticed,Requests sent by btn don't actually need to get a response.The key to the whole process is that the client needs to always keep the server request for connect (). The server first needs to support this asynchronous response method.Fortunately, most servlet containers have provided good support so far.Take tomcat as an example:

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 is a thread-safe implementation of queueIt is used here as a container for holding requests.asynccontext is an asynchronous environment supported by tomcat,Different servers use slightly different objects.Jetty supports continuations. Completed broadcast requests need to end the relevant request through context.complete (),And use connections.remove (context) to delete the queue.

Websocket (support from html5)

A comet that uses http long polling is the best way to reliably implement reverse ajax,Because now all browsers provide this support.

websockets appeared in html5 and is a newer reverse ajax technology than comet. websockets supports two-way, full-duplex communication channels,And many browsers (firefox, google chrome, and safari) also support it.Connections are made via http requests (also known as websockets handshake) and some special headers. The connection is always active,You can write and receive data in javascript,Just as you use raw tcp sockets.

Start the websocket url by entering ws://or wss://(on ssl). As shown in the figure:

First of all:websockets are not well supported on all browsers,Apparently ie dragged on.So when you plan to use this technology, you must consider the user ’s environment,If your project is for the Internet or includes mobile users,We advise you to think twice.

Second:the request provided by websockets is different from ordinary http requests, it is a full-duplex communication and is always active (if you do not close it). This means you don't have to send a request to the server again every time you get a response,This can save a lot of resources.

<%@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" />
<input type="button" value="send" />
</body>
</html>

jquery does not provide better support for websocket,So we must use javascript to write some code (fortunately, it is not complicated). And some common servers can support ws requests, taking tomcat as an example. The websocketservlet object has been marked [email protected] in the 6.0 version. The version after 7.0 supports the implementation provided by jsr365Therefore you must use annotations to complete the relevant configuration.

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) {
}
}
}
}
}

Summary (from request to push)

In traditional communication schemes,If system a needs information from system b,It sends a request to system b.System b will process the request,System a will wait for a response.After processing is complete,The response is sent back to the system a. In synchronous communication mode,Inefficient use of resources,This is because processing time is wasted while waiting for a response.

In asynchronous mode, system a will subscribe to the information it wants to get from system b.System a can then send a notification to system b,You can also return information immediately,at the same time,System a can handle other transactions.This step is optional.In event-driven applications,It is usually not necessary to request other systems to send events,Because you don't know what these events are.After system b publishes the response,System a receives the response immediately.

Web frameworks used to rely on the traditional "request-response" model, which caused page refreshes.With the advent of ajax, reverse ajax, and websocket, the concept of event-driven architecture can now be easily applied to the web, with benefits such as decoupling, scalability, and reactivity. A better user experience will also bring new business opportunities.

  • Previous Deep understanding of JavaScript function parameters (recommended)
  • Next Implementation of JAVA bubble sort and binary search