Январь 27, 2005

Динамическая загрузка данных с помощью HTTPRequest

На первый взгляд, объект HttpRequest не представляет собой нечто особенное. Его возможности раскрываются полностью только тогда, когда вам необходимо сделать запрос GET или POST и обновить при этом только часть страницы. Такая необходимость возникает постоянно, и методы, используемые для достижения цели, далеко не самые оптимальные.

Традиционные пути решения проблемы обновления страницы — полная её перезагрузка. Варианты следующие:

Недостаток всех перечисленных методов состоит в том, что обновление данных влечёт за собой полную перезагрузку страницы. И пользователь при этом обычно теряет текущую позицию просмотра на больших страницах. Кроме того, после перезагрузки теряются изменения, сделанные в других частях страницы (в других формах).

Предположим, что у нас есть страница, являющаяся порталом для управления сайтом. Одна её часть показывает журнал с действиями пользователей, другая – текущую загрузку, и третья отображает большие объёмы данных, которые приходится постоянно прокручивать. Если такая страница будет полностью перезагружаться, то с такой системой управления будет проблематично работать. Одну часть нужной информации мы можем просто пропустить, другую не заметить и т.п.

Одно из решений нашей задачи – фреймы. Работать, конечно, будет, но фреймы решают проблему только визуальной зависимости. Также, иногда мы просто не можем разбить всю систему интерфейса на кучку мелких страничек.

А как же апплеты? Да, апплеты способны эффективно справиться с такой задачей. Но эта технология сейчас не в почёте, и требует установленной виртуальной машины Java ( JVM). Заставлять пользователей её устанавливать или включать не представляется разумным. Другая проблема состоит в том, что апплеты могут общаться только с тем сервером, с которого они были загружены. Сделано это с целью безопасности, однако может существенно ограничить ваши потребности.

На помощь приходит объект HttpRequest

Основная задача объекта HttpRequest – отправлять GET или POST запросы. Давайте взглянем на его свойства и методы:

 Свойство Значение
readyState Состояние документа
status Код ответа HTTP
responseText Результат в виде строки
responseXML Результат в виде XML

 

Метод Значение
open( method, URL, async, user, password ) Создаёт соединение с указанным URL
send( data ) Выполняет запрос

Начнём с методов и их параметров:

Свойства:

Давайте рассмотрим простой пример использования HttpRequest. Код файла test-request.html:


  <html>
    <script>
      var xmlDoc = null ;
  
      function load() {
        if (typeof window.ActiveXObject != 'undefined' ) {
          xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
          xmlDoc.onreadystatechange = process ;
        }
        else {
          xmlDoc = new XMLHttpRequest();
          xmlDoc.onload = process ;
        }
        xmlDoc.open( "GET", "test-request.html", true );
        xmlDoc.send( null );
      }
  
      function process() {
        if ( xmlDoc.readyState != 4 ) return ;
        document.getElementById("output").value = xmlDoc.responseText ;
      }
  
      function empty() {
        document.getElementById("output").value = '' ;
      }
    </script>
  
    <body>
      <textarea id="output" cols="60" rows="20">&lt;empty&gt;</textarea>
      <br></br>
      <button onclick="load()">Load</button> &nbsp;
      <button onclick="empty()">Clear</button>
    </body>
  </html>

Скопируйте данный код и создайте новый HTML-файл. После загрузки этого файла мы увидим пустой элемент textarea с двумя кнопками Load и Clear. После нажатия на кнопку Load отрабатывает функция load(), которая и загружает с помощью HttpRequest файл test-request.html (т.е. тот же самый файл, в данном случае) в область textarea . Функция empty() просто очищает область textarea в первоначальное состояние.

Посмотрим на функцию load():


    function load() {
      if (typeof window.ActiveXObject != 'undefined' ) {
        xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
        xmlDoc.onreadystatechange = process ;
      }
      else {
        xmlDoc = new XMLHttpRequest();
        xmlDoc.onload = process ;
      }
      xmlDoc.open( "GET", "test-request.html", true );
      xmlDoc.send( null );
    }

В этой функции мы создаём новый объект HttpRequest. Заметьте, как мы проверяем браузер: если условие if верно (ActiveXObject есть), значит браузер – MSIE, и нужно создавать версию ActiveX объекта HttpRequest. Если нет, то используется встроенный объект XMLHttpRequest браузера Mozilla. В любом случае после создания объекта ему нужно «приказать» вызвать метод process(), после того, как браузер закончит загрузку страницы. Затем мы вызываем метод open() с необходимыми параметрами (тип запроса – GET, адрес страницы, и асинхронный метод запроса). Запрос отправляется методом send(). Надо отметить, что приведённый код работает в браузерах Internet Explorer 6.0 и Mozilla Firefox 1.0.

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


   if ( xmlDoc.readyState != 4 ) return ;

Этим мы проверяем , обработан ли запрос полностью . И если нет, то нужно просто выйти из функции. Вторая строка просто устанавливает возвращённый результат responseText в textarea.

Заключение

Хотелось бы отметить, что с помощью этого метода можно делать довольно сложные динамические веб-приложения, такие, как почтовая система Gmail, сервис Google Suggest и т.п. Пользователи получают обновления страницы без полной перезагрузки, которая многих просто раздражает.

Единственный недостаток данного механизма по сравнению с апплетами состоит в том, что запрос данных происходит со стороны клиента. Сервер не может уведомить клиента о том, что появились новые данные, которые уже можно загрузить. Соответственно, постоянные запросы могут создать серьёзный трафик.

 

Автор: Дуг Дэвис
Перевод и коррекция: Сергей Яценко

Комментарии

1. 27.01.05 14:40 От: iogan18tm

http://jibbering.com/2002/4/httprequest.html
здесь тоже кое-что написано. В частности в плане кросс-браузерности этого дела. Ну и комментарии по ходу

2. 07.02.05 23:46 От: Илья

Не совсем согласен с фразой автора "Другая проблема состоит в том, что апплеты могут общаться только с тем сервером, с которого они были загружены."
Апплеты можно подписывать (цифровая подпись), тогда появляется возможность обращаться к другим серверам и еще куча возможностей.

3. 20.02.05 23:19 От: Умберто

"JSHttpRequest: динамическая подкачка данных без перезагрузки страницы"
http://dklab.ru/chicken/nablas/41.html
IMHO, там отличное решение (и от других, тоже :)

4. 02.03.05 18:34 От: Петр

Хорошая статья.
dklab тоже молодцы.

5. 04.05.05 17:35 От: intro

То что искал, спасибо

6. 16.08.05 12:36 От: ip

отличная статья.Понятно, а главное на русском!!!

7. 21.12.05 14:17 От: Yurik

а как на шчот Опери

8. 25.01.06 16:25 От: green

Что касается использования технологии

Года 2 назад писал подобную вещь и натолкнулся на ограничение QUERY_STRING по длине - так что "прыгать и хлопать в ладоши" от универсальности метода я не советую

9. 29.01.06 22:44 От: aleksey.stepanov

так отправляй POSTом данные

10. 12.02.06 21:46 От: BF

Люди как POSt'oм отпрамвлять данные просто переменную в SEND'e не укажешь, он её не отправляет, помогите?!?!?!

11. 13.02.06 04:19 От: Big_Foot

Вот решил тут аякса изучить, но пока ума маловато,Люди научите отравлять не гетом а постом, пробовал тут xmlDoc.send( null ) указывать переменную вместо нул, ничего на пхп скрирт который генерит страницу не приходит, или скорее не отправляется, ещё читал где-то что проблемф с русским но до этого думаю рано ещё :-))). Если кто нить может покажите примерчик или ссылочку. ПЛЗ

12. 27.02.06 20:02 От: Nexus

Для того, чтобы передать данные POST-ом, необходимо encode-ить данные. Например, вот так.

request.send(urlEncodeData(data));


function urlEncodeData(data) {
var query = [];
if (data instanceof Object) {
for (var k in data) {
query.push(encodeURIComponent(k) + "=" + encodeURIComponent(data[k]));
}
return query.join('&');
} else {
return encodeURIComponent(data);
}
}

13. 27.02.06 20:04 От: Nexus

data в нашем случае может быть либо обычной переменной, либо ассоциативным массивом

14. 03.09.06 21:24 От: uks

По-моему, про get'ы и post'ы лучше всего читать тут:
http://www.intuit.ru/department/internet/cgi/

15. 20.09.06 14:41 От: pchelovod

Цитата: "Чтобы отправить данные на сервер при помощи запроса POST, параметр data будет содержать наши данные."

Вопрос: В каком формате должны быть передаваемые в скрипт методом POST данные?!

Пытался делать так:
var MyVar="777";
xmlDoc.send(MyVar);

Пытался и так как советовал Nexus. Результат один - вызываемый php-скрипт не видит никаких переменных :(

16. 25.09.06 17:18 От: pchelovod

Отвечаю сам же на свой вопрос :)
"The parameter to the send() method can be any data you want to send to the server if POST-ing the request. The data should be in the form of a query string, like:

name=value&anothername=othervalue&so=on

Note that if you want to POST data, you have to change the MIME type of the request using the following line:

http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
Otherwise, the server will discard the POSTed data. "

Читать тут: http://developer.mozilla.org/en/docs/AJAX:Getting_Started

17. 30.05.07 13:45 От: Vanot

Спасибо!

18. 20.01.09 21:12 От: Валерий Темный

Афтару огромейнейший респект и спасибище!!!! Благодаря вашей статье я реализовал необъятные возможности на своем портале и в 100-ни раз уменьшил нагрузку на сервер!!!

19. 01.02.11 12:20 От: )!(ek@

Офигенно=))
Пасибо...начал врубаться=)

20. 01.11.11 09:06 От: mic

Grazie!
а как xmlDoc.responseText вывести в , чтоб браузер теги обработал?

Ваш комментарий

Обсудить на форуме?

Подумайте, прежде чем высказать своё мнение. Постарайтесь сделать свой комментарий полезным для других. Не используйте ненормативную лексику. Пользователи, пишущие "от нечего делать" бессмысленные наборы символов, будут блокироваться навсегда.