Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > JavaScript, Ajax
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 31.10.2016, 05:16   #1
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию Промежуточный ответ ajax

Доброго времени суток.
Передаю серверу данные используя XMLHttpRequest.
После получения результата типа:
PHP код:
echo json_encode(array('result'=>true'body'=>"http://{$_SERVER['SERVER_NAME']}/ad/material/id/{$ad_id}")); 
декодирую его и как-то обрабатываю.
Но скрипт на сервере достаточно долго работает. Хотелось бы получить какие-нибудь промежуточные сообщения типа (Начинаю..., 10%, 50%, Заканчиваю) и отображать их на экране. Подскажите пожалуйста можно ли это сделать, если да то как?
Вот обработка со стороны клиента:
Код:
if (xhr.readyState == 4) {
	if (xhr.status == 200) {
		var messagejson = JSON.parse(xhr.responseText);
		// Читаем промежуточный ответ
		/* if(messagejson.message) {
			alert("xcvxcv" );
	 	}*/
		if (messagejson.result) {
			window.location.href = messagejson.body;
		} else {
			location.reload()
		}
	}
}
Соответственно если получены промежуточные данные:
PHP код:
echo json_encode(array('message'=>"Начинаю")); 
То скрипт то на сервере ещё выполняется, а клиент уже перестал ждать от него ответа (т.к. уже получил).
OliverVood вне форума Ответить с цитированием
Старый 31.10.2016, 14:37   #2
predefined
Форумчанин
 
Регистрация: 01.08.2016
Сообщений: 182
По умолчанию

Цитата:
Сообщение от OliverVood Посмотреть сообщение
То скрипт то на сервере ещё выполняется, а клиент уже перестал ждать от него ответа (т.к. уже получил).
Надо в цикле продолжать посылать аякс-запросы к серверу, пока от него не придёт финальный ответ.
На хабре расписывали прогресс-бар на аяксе, можно погуглить "прогресс-бар на ajax" и доработать понравившуюся идею под свои нужды.
predefined вне форума Ответить с цитированием
Старый 01.11.2016, 05:26   #3
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Вопрос такой. Как я понял для продолжения приёма данных с сервера вы используете xhr.readyState == 3?
А моя ошибка заключалась в том, что я это пихал в xhr.readyState == 4?

И второй вопрос. С 3 Interactive (xhr.readyState == 3) у браузеров проблем не возникает? В особенности, что касается IE?
OliverVood вне форума Ответить с цитированием
Старый 01.11.2016, 06:41   #4
predefined
Форумчанин
 
Регистрация: 01.08.2016
Сообщений: 182
По умолчанию

Я всегда использую readyState = 4, и по получении данных, по таймеру через 1-2 сек отправляю следующий xhr-запрос за новой порцией данных.

В Интернетах пишут, что с readyState = 3 возникают проблемы:
Цитата:
Вообще, список состояний readyState такой:

0 - Unitialized
1 - Loading
2 - Loaded
3 - Interactive
4 - Complete

Состояния 0-2 вообще не используются.

Вызов функции с состоянием Interactive в теории должен происходить каждый раз при получении очередной порции данных от сервера. Это могло бы быть удобным для обработки ответа по частям, но Internet Explorer не дает доступа к уже полученной части ответа.

Firefox дает такой доступ, но для обработки запроса по частям состояние Interactive все равно неудобно из-за сложностей обнаружения ошибок соединения. Поэтому Interactive тоже не используется.

На практике используется только последнее, Complete.
Поэтому я обрабатываю readyState = 4, ошибку (onerror), и проверяю код ответа сервера xhr.status == 200/401/50x.
predefined вне форума Ответить с цитированием
Старый 01.11.2016, 07:25   #5
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Да, но в приведённой вами статье используется именно readyState == 3?
Я наверно что-то не до понял. Вот как я делаю:
1. Клиент отправляет данные;
2. Сервер обрабатывает их на первом этапе;
3. Сервер шлёт ответ и приступает к выполнению второго этапа не дожидаясь команды от клиента;
4. Клиент тем временем ловит сообщение о пройденном первом этапе;
5. И тут то соединение получается закрылось!? А надо, что-бы клиент ждал следующего сообщения от сервера (пройден этапа 2, 3 и т.д.) ничего ему не пересылая!
Возможно ли это?
В приведённой вами статье говорится что да, но readyState == 3?
OliverVood вне форума Ответить с цитированием
Старый 03.11.2016, 14:47   #6
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

В классическом AJAX клиент посылает запрос и получает ответ и все на этом.
Чтобы порционно получать данные, надо либо пинговать сервер (дедовский способ), либо устанавливать двустороннее соединение (webSocket, стильно, модно, молодежно). Либо ждать окончательного ответа сервера (longpoll, тоже древний метод).
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 04.11.2016, 18:54   #7
predefined
Форумчанин
 
Регистрация: 01.08.2016
Сообщений: 182
По умолчанию

OliverVood, это просто рабочий пример реализации с Хабра. С readyState = 3 возникает всего одна проблема - пока вы ждёте очередной порции данных от сервера - вы не можете определить оборвался канал или нет.

Поэтому ваш алгоритм должен работать вполне нормально (за исключение каммента выше), только надо найти кто и почему рвёт соединение.

Цитата:
5. И тут то соединение получается закрылось!? А надо, что-бы клиент ждал следующего сообщения от сервера (пройден этапа 2, 3 и т.д.) ничего ему не пересылая!
Соединение закрывается не само собой, его кто-то закрывает сервер или клиент.

Вы точно на сервере не делаете exit() или "Connection: close" в headers?

И для протокола HTTP 1.0 надо посылать заголовки "Connection: Keep-Alive". В HTTP 1.1 все соединения считаются постоянными, если не обозначено иное. НО время ожидания по умолчанию в httpd для Apache 1.3 и 2.0 составляет всего 15 секунд, а для Apache 2.2 и 2.4 лишь 5 секунд. После этого соединение рвёт сам сервер.

Не забудьте отключить буферизацию сервером. В связке Apache/PHP - отключите output buffering и включите ob_implicit_flush:
PHP код:
    while (@ob_end_flush()) {}
    
ob_implicit_flush(1);
     
    
// ну и конечно убрать лимит на время выполнения скрипта
    
set_time_limit(0); 
Так же, надо запретить все методы сжатия, сообщить браузеру, что мы передаем поток, и заставить сбрасывать все выводимые данные пользователю - на Хабре есть простой пример серверной и клиентской части, проверьте заработает ли он у вас. Там написано какие заголовки надо послать, чтобы отключить сжатие и буферизацию.


PS: Если нет желания лезть вглубь, ходить по граблям и разбираться с нюансами реализации постоянных соединений - вот тут есть обзор существующих технологий передачи данных по инициативе сервера, обзор COMET - по сути то, что кратко сказал Naive.
Берёте готовое решение, зная его + и - и избегаете "головных болей".

Последний раз редактировалось predefined; 04.11.2016 в 18:57.
predefined вне форума Ответить с цитированием
Старый 04.11.2016, 22:31   #8
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Цитата:
Сообщение от predefined Посмотреть сообщение
Не забудьте отключить буферизацию сервером. В связке Apache/PHP - отключите output buffering и включите ob_implicit_flush:
PHP код:
    while (@ob_end_flush()) {}
    
ob_implicit_flush(1);
     
    
// ну и конечно убрать лимит на время выполнения скрипта
    
set_time_limit(0); 
Попробую, спасибо за ответ.
OliverVood вне форума Ответить с цитированием
Старый 05.11.2016, 18:39   #9
predefined
Форумчанин
 
Регистрация: 01.08.2016
Сообщений: 182
По умолчанию

Цитата:
Сообщение от OliverVood Посмотреть сообщение
Попробую, спасибо за ответ.
Там по ссылке в статье с Хабра есть полный набор нужных заголовков:
PHP код:
header('Content-Encoding: none;'); //вырубаем сжатие
header('Content-type: application/octet-stream'); // мы передаём поток данных

// выключаем буферизацию
ini_set('output_buffering''off');
// выключаем сжатие со стороны php
ini_set('zlib.output_compression'false);
// включаем сброс данных в браузер после каждого вывода
ini_set('implicit_flush'true);
ob_implicit_flush(true);
// закрываем сессию на запись, после этой команды нельзя будет записывать данные в сессию (!)
session_write_close(); 
Сессию тоже надо закрывать(если она открыта), тк PHP не может открыть одну и ту же сессию в двух параллельных потоках, поэтому в случае если ваш процесс будет работать, а пользовать сделает параллельный запрос — он будет висеть в очереди. В итоге все функции AJAX у вас будут парализованы.

Последний раз редактировалось predefined; 05.11.2016 в 18:41.
predefined вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
AJAX, PERL, запись в файл и неожиданный ответ от сервера Jopses JavaScript, Ajax 0 28.02.2013 13:06
Аналог COMPUTE, ROLLUP или как сделать промежуточный итог googl Microsoft Office Access 14 19.01.2012 16:52
AJAX - не подгружается ответ max38934 JavaScript, Ajax 17 19.05.2009 22:34
переместить память из TMemoryStream в промежуточный буфер и в буфере найти слова Дядя Фёдор Общие вопросы Delphi 2 02.10.2007 00:20