|
|
XMLHttpRequest (AJAX) - отправка и обработка ответов http-запросов с помощью JavaScript. |
|
|
|
Автор: Dmitry A. Soshnikov
В интерактивности - статические html сайты - это прошлое. Динамические с
использованием CGI (или модулей сервера, например Apache) и баз данных,
когда сервер при отправки формы формирует страницу и показывает ее после
обновления - чуть современней, но все же во многих областях, где требуется
практически сопостовимая с десктопными приложениями интерактивность - так же
угасают. На смену приходят интерактивные функциональные программы, в полной
мере взаимодействующие с пользователем; информация, полученная от сервера
практически мгновенно отображается на экране без перезагрузке страницы. Речь
я виду об AJAX'e, что в расшифровке "асинхронный JavaScript и XML" (термин
ввел Джесс Гарретт). А если более подробно, то - "асинхронный JavaScript +
CSS + DOM + XMLHttpRequest".
Методы объекта 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>";
}
?>
Ну вот, друзья, собственно, и все на сегодня.
|
|