📜 ⬆️ ⬇️

Asynchronous data exchange over HTTP

Not so long ago, at work, I was tasked with implementing a mechanism for asynchronous data exchange between a Java web application and a web front end on the client side. The task was to ensure that the client received updates with a minimum delay, while updates could come at a speed of 100 updates per second, and 1 update per minute, i.e. It is desirable not to send unnecessary requests from the client.

First, I sketched a test servlet that instantly responded to the request sent from the client on which the request was formed every second. Of course, this scheme was far from ideal, so I began to google.


By the way, the scheme for which it worked:
')


And here's some code from the client (nothing supernatural: timer + sending JSON request):

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


And from the server’s side (in terms of ethical aspects, I cannot disclose the code responsible for the business logic of the application, but the meaning of the article is not in it):

 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(); } 


The first thing I stumbled upon was having articles about Long Polling (I immediately excluded WebSockets , because not all clients can have modern browsers installed). I was very interested in an article on the IBM Developerworks website, where the main points of the organization of asynchronous data exchange between the server and the client using the http protocol are detailed. In the article I drew attention to an interesting example . I advise you to familiarize yourself with it (of course, if you're interested).

As it turned out later in Tomcat, which is used by customers, there is also support for the Comet (Pushing) mechanism. It is implemented by the implementation of the CometProcessor interface. A detailed example is on the Tomcat site, so I recommend to consult the documentation with examples.

In the end, I decided to implement this engine on the server side. I will not give an example, because it differs little from the ones given above (in the links to the articles).

Scheme of work long polling connections:



The main difference from the scheme you saw above is that the server does not send a response immediately, but waits for a certain event. This is achieved by setting the keep-alive tag in the request header. This tag causes the server to not terminate the connection ahead of time. After a response has been sent and the client has received it, the client sends another request again and waits for a response. In fact, here we see a recursive call.

Implement a long polling client on 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); } 


And this would look like using jQuery:
 function poll(){ $.ajax({ url: "your url", success: function(data){ //Something }, dataType: "json", complete: poll, timeout: 30000 }); }); 


Scheme of work stream connections:



Here, as you can see, the client sends only 1 request at the very beginning. And then the server for each event sends a piece of information to the client. This is achieved due to the fact that the writer in response does not close, sending is performed only through the flush () method. Due to this, the client continues to read information from the stream.

Implementing stream client in 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); } 


Additional materials:
1. Wikipedia article on Push Technology
2. Article in English, from where the pictures were called
3. AJAX Patterns (The name says it all)
4. XMLHttpRequest specification

Source: https://habr.com/ru/post/135629/


All Articles