Не так давно на работе мне поставили задачу реализовать механизм асинхронного обмена данными между Java-веб-приложением и клиентским веб-интерфейсом.
Задача была, чтобы клиент получал обновления с минимальной задержкой, при этом обновления могли приходить со скоростью 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();
}
Первое, на что я наткнулся, это статьи о Long Polling ( Вебсокеты Я это сразу исключил, так как не на всех клиентах могут быть установлены современные браузеры).
Меня очень заинтересовала статья на сайте IBM Developerworks, в которой подробно описаны основные моменты организации асинхронного обмена данными между сервером и клиентом по протоколу http. В статье я обратил внимание на интересный пример .
Советую прочитать и вам (если вам интересно, конечно).
Как выяснилось позже, Tomcat, которым пользуются клиенты, также имеет поддержку механизма Comet (Pushing).
Это реализовано путем реализации интерфейса CometProcessor. Подробный пример находится на веб-сайте Tomcat, поэтому я рекомендую проверить документацию на наличие примеров.
В результате я решил реализовать этот движок на стороне сервера.
Пример приводить не буду, потому что он мало чем отличается от приведенных выше (в ссылках на статьи).
Схема работы длинных соединений опроса:
Основное отличие от схемы, которую вы видели выше, заключается в том, что сервер не отправляет ответ сразу, а ждет определенного события.
Это достигается путем размещения тега поддержания активности в заголовке запроса.
Этот тег заставляет сервер не разрывать соединение раньше времени.
После того как ответ отправлен и клиент его получил, клиент снова отправляет еще один запрос и ждет ответа.
По сути, то, что мы здесь видим, — это рекурсивный вызов.
Реализация клиента длительного опроса на 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 запрос.
А затем сервер отправляет клиенту часть информации о каждом событии.
Это достигается за счет того, что писатель в ответе не закрывается; сообщение отправляется только через метод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 #Разработка сайтов
-
Введение В Интерактивный Маркетинг
19 Oct, 24 -
Как Поднять Джунса – Советы Опытного 2Гис
19 Oct, 24 -
Холиварам - Нет?
19 Oct, 24 -
Сериал «Чернобыль»: Смотри И Думай
19 Oct, 24 -
Clrium, Последний Анонс Перед Москвой
19 Oct, 24 -
Обзор Бесплатных Сервисов Для Веб-Разработки
19 Oct, 24