JsHttpRequest: кроссбраузерный AJAX, фоновая закачка файлов, "прозрачное" программирование backend-скриптов Кроссбраузерность, закачка, отладка, многомерные данные, русский язык,... Дмитрий Котеров, архитектор и главный разработчик MoiKrug.ru компания Яндекс
Что такое Web 2.0? © O'Reilly Media, 2004 Браузер есть платформа Данные – движущая сила сайта Демократия среди пользователей, рейтинги, голосования Модель социальной сети Динамическая загрузка данных (AJAX)
AJAX: идеология или просто модное слово? Asynchronous JavaScript And XML Старое название – Remote Scripting Компоненты: –Frontend –Backend
1.Запустить запрос к серверу 2.Продолжить работу 3.Когда придет ответ, запустить обработчик 4.Обработать данные, изменить страницу Сложность AJAX-валидаторов Событийно-ориентированное программирование
Методы динамической загрузки XMLHttpRequest ActiveX невидимый + cookies кто-нибудь знает другие?
Многословный интерфейс Не работает в IE5, IE6, Opera7 Неудобство передачи сложноструктурированных данных Неудобство работы с XML (далее...) var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4) { alert(req.responseText); } } req.open("POST", "xml_backend.php", true); req.send("a=123&b=456");
XMLHttpRequest: обработка XML '; echo ' '. date('r'). ' '; ?> var xml = req.responseXML; var timeNode = xml.getElementsByTagName('time')[0]; alert(timeNode.childNodes[0].nodeValue); Сложно формировать Сложно разбирать Неустойчивость к ошибкам в backend
XMLHttpRequest: АЯКС или АЙАЙ? JSON: генерация json = { "time": "10:00 PM", "date": { "day": 10, "month": "April", "year": 2007 } } PHP: json_encode() JSON: разбор var r; eval("r = " + json); AJAJ – Asynchronous JavaScript and JSON Все еще неустойчивость к ошибкам
XMLHttpRequest: русские кодировки JavaScript – полностью Unicode-язык escape(): кодирование в UCS2BE: %u1234%u5678 –работает даже в очень старых браузерах –сильно увеличивает объем encodeUriComponent(): кодирование в UTF-8 с urlencode: %B2%A3 –работает начиная с IE 5.5+ Однобайтовых кодировок нет
Работает только в IE5, IE6 Должны быть разрешены ActiveX В IE 5.0 иногда возникают проблемы с кодировками (в backend передаются "?")
ActiveX и XMLHttpRequest: кроссбраузерная инициализация var req = null; if (window.XMLHttpRequest) { // Mozilla, Safari и т.д. req = new XMLHttpRequest(); } else if (window.ActiveXObject) { // Internet Explorer с включенными ActiveX. try { req = new ActiveXObject("Msxml2.XMLHTTP") } catch (e) { try { req = new ActiveXObject("Microsoft.XMLHTTP") } catch (e) {} } if (!req) { alert("XMLHttpRequest не поддерживается в этом браузере!"); return; }
var script = document.createElement('script'); script.src = 'script_backend.php?id=1&a=123'; document.appendChild(script); dataReady({ id: " ", data: });
: проблемы : проблемы Поддерживается только GET Нельзя передать много данных Нужно явно передавать ID Opera: загрузка - блокирующая (синхронная) операция Opera: только div.innerHTML = 'text ' В некоторых браузерах не работает вообще (например, Opera 7.10)
var iframe = document.createElement('iframe'); iframe.name = 'dyna'; document.appendChild(iframe); form.target = iframe.name; form.submit(); dataReady({ id: " ", data: });
: плюсы и минусы : плюсы и минусы Плюсы –нет проблем с русскими кодировками –отправка формы целиком –поддержка методов GET и POST –можно закачивать файлы element.cloneNode() не работает в Safari для файловых полей Минусы –щелчок –засорение history –баги в FF с кнопкой Назад –большой расход памяти –плохая кроссбраузерность
+ cookies + cookies var img = document.createElement('img'); img.src = 'img_backend.php?id=1&a=123'; img.onload = function () { alert(document.cookies); } document.appendChild(img); Исключительно высокая кроссбраузерность! Но: должны быть включены cookies
Обзор всех методов: проблемы Совершенно разные интерфейсы Трудно передавать сложные данные: { some: value, other: { key: value } } Трудно принимать сложные данные Разные методы для разных браузеров Русскоязычные кодировки Обработка ошибок в backend
Есть ли решение? ДА! JsHttpRequest решает все перечисленные проблемы
Упрощенный интерфейс вызова // Frontend: JavaScript JsHttpRequest.query( address, // путь до backend data, // массив/объект JavaScript onreadyfunc(result, errors), // callback nocache // если true, кэш запрещен ); // Backend: PHP require_once 'JsHttpRequest/JsHttpRequest.php"; $JsHttpRequest =& new JsHttpRequest("windows-1251");... // Получаем данные из $_GET, $_POST, $_FILES, $_REQUEST... global $_RESULT; $_RESULT = array(данные для frontend-а)
Пример: suggest (frontend) JsHttpRequest.query( // Адрес backend-сценария. 'suggest_backend.php', // Так передаются параметры backend-у { 'str': st, // первые буквы слова 'num': 10 // число элементов списка для вывода }, // Функция вызывается, когда backend подготовил данные. function(result, errors) { // Записать сообщения об ошибках в. document.getElementById("debug").innerHTML = errors; // Сформировать результат. var list = document.getElementById("list"); list.length = 0; // удалить все строки списка for (var i = 0; i < result.list.length; i++) { list[i] = new Option(result.list[i]); } }, // Не запрещать кэширование одинаковых запросов. false );
Пример: suggest (backend)
Закачка файлов "AJAX-ом" Проблема безопасности Библиотеке передается не файл, а элемент выбора файла Проблема в Safari: нельзя клонировать и перемещать в другую форму
Закачка файлов "AJAX-ом"... JsHttpRequest.query( 'backend.php', { 'str': { nested: st }, 'upl': document.getElementById('e_file') }, function(result, errors) {... } );
Отправка формы целиком... JsHttpRequest.query( 'backend.php', document.getElementById('e_form') function(result, errors) {... } );
Русскоязычные кодировки Работа с кодировками полностью прозрачна как для frontend, так и для backend JsHttpRequest может работать с windows-1251 и koi8-r и при отсутствии iconv (собственные таблицы) Для ускорения в PHP 5.2 автоматически используется json_encode()
Работа с сессиями полностью прозрачна и происходит стандартными средствами PHP
Выбор метода и загрузчика JsHttpRequest.query( 'GET backend.php',... ); JsHttpRequest.query( 'xml.POST backend.php',... ); JsHttpRequest.query( ' ); По умолчанию выбирается наилучший загрузчик и метод, совместимые с браузером Возможна загрузка с "чужого" домена (script, form)
Четвертый параметр JsHttpRequest.query(). Если кэширование включено, то при попытке повторной загрузки по тому же самому запросу данные берутся из кэша. Не работает для закачки файлов, а также для отправки формы целиком.
Отладка и перехват ошибок в backend JsHttpRequest.query( 'backend.php', {... }, function(result, errors) { if (errors) alert(errors); } ); Кто сказал, что фатальные ошибки PHP нельзя перехватить?
Отладка и перехват ошибок в backend Пример данных, сгенерированных backend-ом JsHttpRequest.dataReady({ "id": "123", "js": { "str": "строка",... }, "text": "Сообщения и ошибки." })
Ошибки во frontend Все ошибки генерируются в виде исключений JavaScript: throw new Error(...) 1.'Invalid FORM element detected: name=%, tag=%', 2.'If used, must be a single HTML element in the list.', 3.'JavaScript code generated by backend is invalid!\n%', 4.'Cannot use so long query with GET request (URL is larger than % bytes)', 5.'Unknown loader: %', 6.'No loaders registered at all, please check JsHttpRequest.LOADERS array', 7.'Cannot find a loader which may process the request. Notices are:\n%', 8.'Method setRequestHeader() cannot work together with the % loader.' 9.'Cannot use XMLHttpRequest or ActiveX loader: not supported', 10.'Cannot use XMLHttpRequest to load data from different domain %', 11.'Cannot use XMLHttpRequest loader or ActiveX loader, POST method: headers setting is not supported, needed to work with encodings correctly', 12.'Cannot use XMLHttpRequest loader: direct form elements using and uploading are not implemented' 13.'Cannot use SCRIPT loader: it supports only GET method', 14.'Cannot use SCRIPT loader: direct form elements using and uploading are not implemented' 15.'Element "%" does not belong to any form!', 16.'Element "%" belongs to a different form. All elements must belong to the same form!', 17.'Attribute "enctype" of the form must be "%" (for IE), "%" given.'
Интерфейс, совместимый с XMLHttpRequest var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4) { alert(req.responseText); } req.open("GET", 'backend.php', true); req.send(null); var req = new JsHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4) { alert(req.responseText); } req.open("GET", 'backend.php', true); req.send(null); Найдите 10 отличий… Элементарная интеграция с prototype js Легкая миграция существующих приложений
Модульная архитектура Код библиотеки состоит из частей: –Базовый модуль (неотключаемый) –Модуль поддержки XML –Модуль поддержки script –Модуль поддержки form Любой модуль можно удалить из кода даже "вручную" mini/JsHttpRequest-script.js: только загрузчик script (8.2К) mini/JsHttpRequest-script-xml.js: только script и xml debug/*.js: полные версии исходников с комментариями mini/*.js: "минимизированные" версии (dojomin) "Минимизированная" версия со всеми загрузчиками: 14К
Обеспечение кроссбраузерности Автоматизированный test framework На каждый багфикс – один тест На каждую сгенерированную ошибку – один тест Главная сложность при тестировании – принципиальная асинхронность
Backend-ы на не-PHP За время существования библиотеки зарегистрированы случаи создания умельцами backend-модулей на: –perl –c –parser К сожалению, все они не дотягивают до production-версий Но никаких препятствий нет!
Кроссбраузерность (IE5.0+ без ActiveX, Mozilla 1.7+, Firefox 1.0+, Opera 7.20+, Safari) Прозрачная работа с русскими кодировками Закачка файлов методом AJAX Поддержка отладочных возможностей PHP Двусторонняя передача многомерных структур PHP JavaScript Поддержка сессий PHP Выбор оптимального загрузчика Компонентность Совместимый с XMLHttpRequest интерфейс
Приходите к нам работать! МойКруг.ру теперь – сервис Яндекса Мы расширяем свою команду! Открыты вакансии для: –верстальщиков со знанием Smarty –отличных PHP-программистов Ждем Ваши резюме на