Асинхронная Связь Через Http

Не так давно на работе мне поставили задачу реализовать механизм асинхронного обмена данными между Java-веб-приложением и клиентским веб-интерфейсом.

Задача была, чтобы клиент получал обновления с минимальной задержкой, при этом обновления могли приходить со скоростью 100 обновлений в секунду, или 1 обновление в минуту, т.е.

желательно не отправлять лишние запросы от клиента.

Сначала я набросал тестовый сервлет, который мгновенно отвечал на запрос, отправленный от клиента, на котором этот запрос генерировался каждую секунду.

Конечно, эта схема была далека от идеала, поэтому я начал гуглить.

Кстати, схема, по которой это работало:

Асинхронная связь через HTTP

А вот код со стороны клиента (ничего сверхъестественного: таймер + отправка 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(); }

Первое, на что я наткнулся, это статьи о Long Polling ( Вебсокеты Я это сразу исключил, так как не на всех клиентах могут быть установлены современные браузеры).

Меня очень заинтересовала статья на сайте IBM Developerworks, в которой подробно описаны основные моменты организации асинхронного обмена данными между сервером и клиентом по протоколу http. В статье я обратил внимание на интересный пример .

Советую прочитать и вам (если вам интересно, конечно).

Как выяснилось позже, Tomcat, которым пользуются клиенты, также имеет поддержку механизма Comet (Pushing).

Это реализовано путем реализации интерфейса CometProcessor. Подробный пример находится на веб-сайте Tomcat, поэтому я рекомендую проверить документацию на наличие примеров.

В результате я решил реализовать этот движок на стороне сервера.

Пример приводить не буду, потому что он мало чем отличается от приведенных выше (в ссылках на статьи).

Схема работы длинных соединений опроса:

Асинхронная связь через HTTP

Основное отличие от схемы, которую вы видели выше, заключается в том, что сервер не отправляет ответ сразу, а ждет определенного события.

Это достигается путем размещения тега поддержания активности в заголовке запроса.

Этот тег заставляет сервер не разрывать соединение раньше времени.

После того как ответ отправлен и клиент его получил, клиент снова отправляет еще один запрос и ждет ответа.

По сути, то, что мы здесь видим, — это рекурсивный вызов.

Реализация клиента длительного опроса на 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 }); });

Схема работы подключения потока:

Асинхронная связь через HTTP

Здесь, как видите, клиент в самом начале отправляет всего 1 запрос.

А затем сервер отправляет клиенту часть информации о каждом событии.

Это достигается за счет того, что писатель в ответе не закрывается; сообщение отправляется только через методlush().

Благодаря этому клиент продолжает читать информацию из потока.

Реализация потокового клиента на 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. Статья в Википедии o Нажмите Технология 2. Статья на английском языке, откуда взяты картинки 3. AJAX-шаблоны (Название говорит само за себя) 4. Спецификация на XMLHttpRequest Теги: #java #JavaScript #jQuery #Ajax #Разработка сайтов

Вместе с данным постом часто просматривают: