Лабораторная работа: XMLHttpRequest (AJAX)
Лабораторная работа: XMLHttpRequest (AJAX)
Кафедра: АСОИиУ
Лабораторная Работа
На тему: XMLHttpRequest (AJAX)
XMLHttpRequest (AJAX) - отправка
и обработка ответов http-запросов с помощью JavaScript
Методы объекта XMLHttpRequest
Все
нижеизложанные методы и свойства - общие для Internet Explorer 5, Mozilla,
Netscape 7, и соответственно, использовать их можно безопасно.
abort()
обрывает
текущий запрос
getAllResponseHeaders()
возвращает
полный набор заголовков ответа (названий и значений) в виде строки
getResponseHeader(<headerLabel>)
возвращает
строковое значение заголовка, название которого указано в параметре.
open(<method>, <URL> [, <asyncFlag> [, <userName> [, <password>]]])
Присвоение
параметров (метода, URL, и других) текущему запросу.
send(<content>)
Посылает запрос
setRequestHeader(<label>, <value>)
Установка в
отправляемом запросе заголовка <label> со значением <value>
Свойства
объекта XMLHttpRequest
onreadystatechange
событие,
возникающее при смене статуса объекта
readyState
значения
статуса (integer), может принимать следующие значения: 0 = неинициализирован
(uninitialized); 1 = "идет загрузка" (loading); 2 = "загружен"
(loaded); 3 = "интерактивен" (interactive) 4 = "выполнен"
(complete)
responseText
строка с
возвращенными сервером данными
responseXML
DOM-совместимый
объект-документ с возвращенными сервером данными
status
стандартный
HTTP код статуса, например 404 (для "Not Found") или 200 (для "OK")
statusText
текстовое
сообщение статуса
Здесь все
необходимые свойства и методы этого объекта, которые помогут нам решить наш
таск. Опишем последовательность наших действий:
Алгоритм:
1. Создание
экземпляра объекта XMLHttpRequest.
2. Объявление
обработчика события onreadystatechange нашего экземпляра.
3. Открытие
соединения с указанием типа запроса, URL и других параметров.
4. Посыл
запроса.
Алгоритм
незамысловат, но, учитывая кое-какие нюансы (и учитывая, что мы учимся:)),
конечно же, рассмотрим его подробней:
Итак, пункт
первый - создание экземпляра объекта. Вот здесь всплывает особенность
обеспечения кроссбраузерности. Конструкция создания объекта различна: в IE 5+
она реализована через ActiveXObject, а в остальных браузерах (Mozilla, Netscape
и Safari) - как встроенный объект типа XMLHttpRequest.
Для Internet Explorer:
var request = new ActiveXObject("Microsoft. XMLHTTP");
Для всех
остальных:
var request =
new XMLHttpRequest();
Таким
образом, чтобы обеспечить кроссбраузерность, нужно лишь проверять наличие
объектов window. XMLHttpRequest и window. ActiveXObject и применять
соответствующий вызов создания экземпляра.
Далее по
плану - создание обработчика событий и открытие соединения. Это весьма просто:
request. onreadystatechange = processRequestChange;
request. open("GET", url, false);
Здесь мы
используем метод GET, хотя можно и POST; в общем виде это выглядет так: request.
open(<"GET"|"POST"|... >, <url>, <asyncFlag>);.
Функцию, являющуюся обработчиком события onreadystatechange (в нашем случае это
функция - processRequestChange()), мы должны определить сами.
Ну и
последний пункт - посыл запроса - метод send() (для версии без ActiveX в
качестве параметра нужно передать null).
// для IE
request. send();
// для
остальных
request. send(null);
После
запуска метода send() начинает работать вышеуказанный обработчик события
onreadystatechange. Собственно, этот обработчик - основная часть программы. В
нем обычно перехватываются все возможные коды состояния запроса и вызываются
соответствующие действия, а также перехватываются возможные ошибки.
Исходя из
всего вышесказанного, JavaScript код будет примерно следущим:
var request;
/**
* Load
XMLDoc function
* Здесь в
качестве параметра url при вызове мы должны указать
*
backend-скрипт, который, собственно, и получит данные с сервера
*/
function doLoad(url) {
if (window. XMLHttpRequest) {
request = new XMLHttpRequest();
request. onreadystatechange = processRequestChange;
request. open("GET", url, true);
request. send(null);
} else if (window. ActiveXObject) {
request = new ActiveXObject("Microsoft. XMLHTTP");
if (request) {
request. onreadystatechange = processRequestChange;
request. open("GET", url, true);
request. send();
}
}
}
/**
* Get request state text function
*/
function getRequestStateText(code) {
switch (code) {
case 0: return "Uninitialized. "; break;
case 1: return "Loading... "; break;
case 2: return "Loaded. "; break;
case 3: return "Interactive... "; break;
case 4: return "Complete. "; break;
}
}
/**
* Event on request change
* Собственно, обработчик события onreadystatechange.
* Здесь мы,
в зависимости от состояния запроса,
* будем
скрывать / показывать слои "Загрузка данных",
* само поле
данных и т.д.
*/
function processRequestChange() {
document. getElementById("resultdiv"). style. display =
'none';
document. getElementById("state"). value =
getRequestStateText(request. readyState);
abortRequest = window. setTimeout("request. abort(); ",
10000);
// если выполнен
if (request. readyState == 4) {
clearTimeout(abortRequest);
document. getElementById("statuscode"). value = request. status;
document. getElementById("statustext"). value = request. statusText;
// если успешно
if (request. status == 200) {
document. getElementById("resultdiv"). style. display =
'block';
document. getElementById("responseHTML"). innerHTML =
request. responseText;
} else {
alert("Не
удалось получить данные: n" + request. statusText);
}
document. getElementById("loading"). style. display =
'none';
}
// иначе,
если идет загрузка или в процессе - показываем слой "Загружаются данные"
else if (request. readyState == 3 || request. readyState == 1) {
document. getElementById("loading"). style. display =
'block';
}
}
Теперь
HTML-формы нашего примера:
<input type="text"
id="search"
value="Введите
первые буквы ника"
onFocus="this. value=''; document. getElementById('resultdiv').
style. display='none'; "
/>
<input type="button"
value="Поиск"
onClick="doLoad('ajaxsearch. php? search='+document. getElementById('search').
value);"
/><br
/><br />
Дополнительная
информация о выполнении запроса: <br /><br />
<table>
<tr>
<td>Состояние
запроса: </td>
<td><input type="text" id="state"
disabled="true" /></td>
</tr>
<tr>
<td>Код статуса: </td>
<td>
<input type="text" id="statuscode" disabled="true"
/>
<input type="text" id="statustext" disabled="true"
/>
</td>
</tr>
</table>
Обратите
внимание на фрагмент, выделенный зеленным цветом - событие onClick кнопки "Поиск".
Мы вызываем функцию doLoad(. .), в качестве параметра которой передаем адрес
backend-скрипта, выполняющего поиск в базе зарегистрированного пользователя. О
backend-скрипе чуть позже, имя его мы определили как ajaxsearch. php. Также
GET-параметром скрипту мы передаем переменную search, со значением, взятым из
поля ввода для ника.
И, как было
сказано выше, объявим дополнительные HTML-элементы (в нашем случае - это
невидимые слои) для отображения полученного содержимого и окна загрузки с
возможностью отмены:
<div id="resultdiv" style="display: none; ">
Резульаты поиска:
<span id="responseHTML"></span>
</div>
<div id="loading"
style="
position: absolute;
top: 450px;
left: 550px;
display: none;
width: 125px;
height: 40px;
font-family: Verdana;
font-size: 11pt;
border: 1px solid #BBBBBB;
background: #EEEEEE;
padding: 5px 5px 5px 5px;
"
>
Loading data...
<div id="canselloading"
style="
background: red;
border: 1px solid #000000;
color: #FFFFFF;
padding: 2px 2px 2px 2px;
cursor: pointer;
"
onClick="
request. abort();
document. getElementById('loading'). style. display = 'none';
return false;
"
>Cansel
</div>
</div>
Ну что ж, с
frontend'ом разобрались, переходим к backend'у - скрипт ajaxsearch. php. И
вновь мы сталкиваемся с небольшими нюансами: для того, чтобы PHP-скрипт корректно
работал с XMLHttpRequest, он (скрипт) должен посылать ряд заголовков. А именно:
тип содержимого и его кодировку (особенно важно, если вы работаете с кириллицей),
а также параметры кеширования - любое кеширование должно быть отключено (ну это
и понятно - необходимо иметь свежую информацию).
Послать эти
заголовки можно, примерно, так:
header("Content-type: text/html; charset=windows-1251");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
И еще одна
особенность: если вы будете выводит данные в формате text/plane (в нашем случае
- text/html, поэтому нас это не каснется, но все же - чтобы знать), помните,
что спецсимволы такие как n, t, r и т.д., обрабатываются по умолчанию только в
строках с двойными кавычками:
// т.е. правильно
так
print "MessagenFrom AJAX";
// а не так!
print 'MessagenFrom AJAX';
Ну и теперь
весьма банальный PHP-скрипт получения данных из базы (а банальный, потому что
предполагается, что у вас уже есть навыки работы с базами данных в PHP). Вид
скрипта следующий (в найденых никах мы подсвечиваем буквы запроса красным
цветом и выводим все это в виде таблицы):
<? php
/**
* Посыл заголовков
*/
header("Content-type: text/plain; charset=windows-1251");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
/**
* Хост,
логин и пароль базы данных
* (вам,
естественно, нужно заменить на свои значения)
*/
$dbhost = "localhost";
$dblogin = "root";
$dbpassword = "root";
/**
*
Коннектимся к базе, выполняем
* запрос,
получаем результат
*/
@mysql_connect($dbhost, $dblogin, $dbpassword) or die("Unable
to connect to database. ");
@mysql_select_db("MYDATABASE") or die("Unable to
select database");
$sql = "SELECT * FROM users WHERE nick LIKE '%". $_GET
["search"]. "%' ORDER BY nick";
$result = mysql_query($sql);
print "Найдено по запросу: ". mysql_num_rows($result);
/**
* Если есть
ряды, выводим таблицу
*/
if (mysql_num_rows($result) > 0) {
print "<table>";
print "<tr>";
print "<td>NickName</td>";
print "<td>RealName</td>";
print "<td>E-mail</td>";
print "</tr>";
$get = $_GET ["search"] ;
while ($row = mysql_fetch_array($result)) {
print "<tr>";
print "<td>";
print ($row ["unick"] ? preg_replace("/($get) /i",
"<font color='red'>1</font>", $row ["unick"]):"
");
print "</td>";
print "<td>($row ["urealname"] ? $row ["urealname"]:
" ") </td>";
print "<td>$row ["umail"] </td>";
print "</tr>";
}
print "</table>";
}
? >