AJAX: низкий уровень

22 Jul 2007

Если верить некоторым комментариям, то этот блог читают хардкорные программисты, которые изучили фреймворки и сочли, что лучшим решением в случае технологии Ajax является прямое программирование через XMLHttpRequest Есть в этом доля правды: фреймворки тоже писали простые смертные, а найти их ошибку может быть очень сложно. Давайте рассмотрим прямые методы асинхронного доступа в JavaScript пошагово и тщательно на основе спецификаций примерно в таком прядке:

  • Что такое AJAX вообще и в чём суть.
  • “Скажите “Пожалуйста!” или “Как послать HTTP-запрос”.
  • “Сделано!” или “Обрабатываем ответ сервера”.
  • “А теперь вместе!” или “Простой пример”.
  • “X-Files” или “Работа с XML-ответом”.

Что такое AJAX вообще и в чём суть?

Ajax — это “Asynchronous JavaScript and XML” (Асинхронный JavaScript и XML). В основе технологии лежит использование нестандартного объекта XMLHttpRequest(), необходимого для взаимодействия со скриптами на стороне сервера. Объект может как отправлять, так и получать информацию в различных форматах включая XML, HTML и даже текст. Самое привлекательное в Ajax — это его асинхронный принцип работы. С помощью этой технологии можно осуществлять взаимодействие с сервером без необходимости перезагрузки страницы, что позволяет обновлять содержимое страницы частично, в зависимости от действий пользователя. Мы рассмотрим две особенности, с помощью которых можно:

  • Отправлять запросы серверу без перезагрузки страницы.
  • Работать с XML документами.

Скажите “Пожалуйста!” или “Как послать HTTP-запрос”.

Для того, чтобы послать HTTP запрос из JavaScript, необходим экземпляр класса, который поддерживает такую функцию. Такой класс впервые был введен в Internet Explorer как объект ActiveX, называемый XMLHTTP. Позже в Mozilla, Safari и другие броузеры был введен класс XMLHttpRequest, который поддерживал методы и свойства изначального объекта ActiveX от Microsoft. В результате, чтобы создать кросс-браузерный объект, можно сделать следующее:

if (window.XMLHttpRequest){// Mozilla, Safari, ...
http_request = new XMLHttpRequest(; }
else if (window.ActiveXObject){// IE
http_request = new ActiveXObject("Microsoft.XMLHTTP"); }

(Ради наглядности этот код немного упрощен. Более правильный пример будет рассмотрен далее). Некоторые версии браузеров Mozilla не будут корректно работать, если ответ сервера не содержит заголовка XML mime-type. Чтобы решить эту проблему можно использовать переопределение заголовка полученного от сервера.

http_request = new XMLHttpRequest();
http_request.overrideMimeType('text/xml');

Далее необходимо указать объекту, какая функция будет обрабатывать ответ. Это делается путем присваивания свойству onreadystatechange имени JavaScript функции, которую вы собираетесь использовать:

http_request.onreadystatechange = nameOfTheFunction;

После названия функции нет скобок, ни параметров, потому что вы просто присваиваете ссылку на функцию, а не вызываете ее. К тому же, вместо указания имени функции можно использовать возможность JavaScript объявлять функции на лету («анонимные функции») и указывать действия, которые сразу же будут обрабатывать ответ:

http_request.onreadystatechange = function(){
// код функции
};

После этого необходимо сделать запрос. Нужно вызвать методы класса open() и send():

http_request.open('GET' , 'http://www.example.org/some.file' , true);
http_request.send(null);

  • Первый параметр вызова функции open() — метод запроса HTTP (GET, POST, HEAD или любой другой поддерживаемый). Используйте методы в соответствии с HTTP-стандартами. Информация о допустимых HTTP запросах доступна по адресу спецификации W3C.
  • Второй параметр — URL запрашиваемой страницы. Из соображений безопасности нельзя запрашивать страницы сторонних доменов. Типичной ошибкой при доступе к сайту site.ru является подача запросов на www.site.ru. Особым ограничением это не является – ведь сам скрипт (на PHP, например) вполне может обращаться куда угодно.
  • Третий параметр указывает, является ли запрос асинхронным. Если он TRUE, то выполнение JavaScript продолжится во время ожидания ответа сервера.

Параметром метода send() могут быть любые данные, которые вы хотите послать на сервер. Данные должны быть сформированы в строку запроса:

name=value&anothername=othervalue&so=on

Заметьте, что если вы хотите отправить данные методом POST, вы должны изменить MIME-тип запроса с помощью следующей строки:

http_request.setRequestHeader('Content-Type' , 'application/x-www-form-urlencoded');

Иначе сервер проигнорирует данные отправленные методом POST.

“Сделано!” или “Обрабатываем ответ сервера”.

Вернёмся к функции, имя которой мы указали в качестве обрабатывающей ответ.

http_request.onreadystatechange = nameOfTheFunction;

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

if (http_request.readyState == 4){
// ответ получен
}else{
// еще не готово или что-то не так
}

Полный список значений кодов readyState такой:

  • 0 – uninitialized.
  • 1 – loading.
  • 2 – loaded.
  • 3 – interactive.
  • 4 – complete.

(Источник)


Следующее, что нужно проверить — это статус HTTP-ответа. Все возможные коды можно посмотреть на сайте W3C. Нам интересен только код ответа 200 OK.

if (http_request.status == 200){
// то что нужно
}else{
// проблемы, например, 404 (Не найдено) или 500 (Внутренняя ошибка сервера)
}

Теперь, после проверки состояния запроса и статуса HTTP-ответа, вы можете делать с полученными данными все что угодно. Есть два способа получить к ним доступ:

  • http_request.responseText – возвращает ответ сервера в виде строки текста.
  • http_request.responseXML – возвращает ответ сервера в виде объекта XMLDocument, который вы можете обходить используя функции JavaScript DOM.

“А теперь вместе!” или “Простой пример”.

Теперь соберем все вместе и сделаем простой пример HTTP-запроса. Наш JavaScript запросит HTML документ test.html, который содержит текст “I’m a test.” и выведет содержимое файла в диалоговом окне.

<script type="text/javascript" language="javascript">
function makeRequest(url>){
var httpRequest;
if (window.XMLHttpRequest){// Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
if (httpRequest.overrideMimeType){
httpRequest.overrideMimeType('text/xml');
}
}
else if (window.ActiveXObject){// IE
try{
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e){
try{
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e){}
}
}
if (!httpRequest){
alert('Не могу создать экземпляр XMLHTTP');
return false;
}
httpRequest.onreadystatechange = function(){alertContents(httpRequest; };
httpRequest.open('GET', url, true);
httpRequest.send('');
}
function alertContents(httpRequest){
if (httpRequest.readyState == 4){
if (httpRequest.status == 200){
alert(httpRequest.responseText);
}else{
alert('Проблема с запросом.');
}
}
}
</script>
<span style="cursor: pointer; text-decoration: underline" onclick="makeRequest('test.html')">
Make a request
</span>

В этом примере:

  • Пользователь нажимает на ссылку “Сделать запрос” в броузере;
  • Это вызывает функцию makeRequest() с параметром test.html — именем HTML файла;
  • Посылается запрос, после чего (onreadystatechange) выполнение передается alertContents();
  • alertContents() проверяет получен ли ответ и все ли с ним в порядке, после чего содержимое файла test.html выводится в диалоговом окне.

Вы можете посмотреть пример в действии здесь.

Тонкости:

1. Строка http_request.overrideMimeType(‘text/xml’); вызовет ошибки в консоли JavaScript в Firefox 1.5 или более позднем (https://bugzilla.mozilla.org/show_bug.cgi?id=311724), если страница вызванная с помощью XMLHttpRequest, не является правильным XML (например, если это обычный текст). В принципе, это корректное поведение.

2. Если вы посылаете запрос не на статический XML-файл, а на серверный скрипт, возвращающий XML, то нужно установить некоторые заголовки ответа, если вы планируете сделать вашу страницу работоспособной в Internet Explorer. Если вы не установите заголовок Content-Type: application/xml, IE будет сообщать об ошибке JavaScript, ‘Object Expected’, после строки, где вы пытаетесь получить доступ к XML элементу. Если вы не установите заголовок Cache-Control: no-cache, то броузер будет кэшировать ответ и никогда не будет повторно отправлять запрос ссделав отладку весьма увлекательной.

3. Если переменная http_request используется глобально, то конкурирующие функции, вызывающие makeRequest() могут конкурировать друг с другом. Объявление переменной http_request локально в функции и передача ее в alertContent() предотвращает это.

4. При привязывании функции обратного вызова к onreadystatechange нельзя указывать аргументов. По этой причине не работает следующий код:

http_request.onreadystatechange = alertContents(http_request; // Не работает.

Таким образом, для успешной регистрации функции, вы должны передать ей аргументы косвенно через анонимную функцию или используя http_request как глобальную переменную. Например:

http_request.onreadystatechange = function(){alertContents(http_request;)}; // 1 (одновременный запрос)
http_request.onreadystatechange = alertContents; // 2 (глобальная переменная)

Первый способ позволяет делать несколько запросов одновременно, а второй используется, когда переменная http_request является глобальной.

5. В случае ошибки взаимодействия (например, проблемы с сервером), при попытке доступа к переменной .status метода onreadystatechange будет сгенерировано исключение. Убедитесь, что if…then заключено в попытку – try…catch. (https://bugzilla.mozilla.org/show_bug.cgi?id=238559).

function alertContents(httpRequest){
try{
if (httpRequest.readyState == 4){
if (httpRequest.status == 200){
alert(httpRequest.responseText);
}else{
alert('Проблема с запросом.');
}
}
}
catch( e ){
alert('Исключение: '+ e.description);
}
}

“X-Files” или “Работа с XML-ответом”.

В предыдущем примере, после того как был получен ответ на HTTP-запрос мы использовали responseText запрашиваемого объекта, который содержал данные файла test.html. Теперь попробуем использовать свойство responseXML. Прежде всего, давайте создадим правильный XML документ, который мы будем запрашивать. Документ (test.xml) содержит следующее:

<?xml version="1.0"?><root> I'm a test.</root>

В скрипте необходимо всего лишь заменить строку запроса на:

onclick="makeRequest('test.xml')">

Далее в alertContents() нам нужно заменить строку alert(http_request.responseText); на:

var xmldoc = http_request.responseXML; var root_node = xmldoc.getElementsByTagName('root').item(0); alert(root_node.firstChild.data);

Этот код берет объект XMLDocument, возвращаемый responseXML и использует методы DOM для доступа к данным, содержащимся в документе XML. Посмотреть test.xml можно здесь, а обновленный скрипт здесь.

Чтобы узнать больше о методах DOM, изучите реализацию DOM в Mozilla.

Англоязычный источник: http://developer.mozilla.org / en/docs/AJAX:Getting_Started.






 

Павел     .

Написано 22 июля 2007 года в 05:26


По моему можно обойтись без велосипедов JavaScript библиотекой tw-sack.
На ней все те-же самое будет выглядеть так
function test(URL) {
var ajax = new sack();
ajax.AjaxFailedAlert = “Don’t work JavaScript”; // На случай не работающего JavaScript
ajax.requestFile = URL; // К какому файлу обращаемся
ajax.method = “POST”; // Или GET или HEAD
ajax.setVar(“test”, “1″); // Посылается $_POST['test']
ajax.element = ‘data’; // ID элемента в который будет выводится результат
onLoading = loading(‘data’); // ID элемента, в который на время загрузки данных будет выводится результат работы функции loading()
ajax.runAJAX();
}

 

lugavchik@livejournal     .

Написано 22 июля 2007 года в 08:16


может всё таки:
http_request.onreadystatechange = function(){alertContents(http_request; }; // 1 (одновременный запрос)
тут пропущена “)”
и должно быть так:
http_request.onreadystatechange = function(){alertContents(http_request); }; // 1 (одновременный запрос)

 

Жилинcкий Владимир     .

Написано 22 июля 2007 года в 09:10


Спасибо, поправил.

 

Жилинcкий Владимир     .

Написано 22 июля 2007 года в 09:12


Похоже, умники в комментариях неистребимы…

 

steward1@livejournal     .

Написано 22 июля 2007 года в 11:13


Внимательно прочитайте первый абзац и будет вам счастье :)

 

Артём Курапов     .

Написано 22 июля 2007 года в 12:09


XML это громоздко – попробуйте JSON.

 

Жилинcкий Владимир     .

Написано 22 июля 2007 года в 12:16


В тему, спасибо !

© 2007-2010 Блог интернет-разработчика, автор — Zhilinsky.ru.
При использовании информации ссылка на источник обязательна.



Газонокосилка со склада в москве. , Оригинальные запчасти и заводская сборка. Надежные и мощные автомобили фольксваген multivan.
Дизайн сайта
DIZ Balance
  Яндекс.Метрика
 PR&CY Checker
Рейтинг блогов
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483