js http request дмитрий котеров

37
JsHttpRequest: JsHttpRequest: кроссбраузерный кроссбраузерный AJAX, AJAX, фоновая фоновая закачка файлов, "прозрачное" закачка файлов, "прозрачное" программирование программирование backend- backend- скриптов скриптов Кроссбраузерность, закачка, Кроссбраузерность, закачка, отладка отладка , , многомерные данные, многомерные данные, русский язык, ... русский язык, ... Дмитрий Котеров, Дмитрий Котеров, архитектор и главный разработчик архитектор и главный разработчик MoiKrug.ru MoiKrug.ru компания Яндекс компания Яндекс [email protected] [email protected]

Upload: webcrunch

Post on 17-Jan-2015

4.708 views

Category:

Technology


11 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Js Http Request   дмитрий котеров

JsHttpRequest: JsHttpRequest: кроссбраузерный кроссбраузерный AJAX,AJAX, фоноваяфоновая закачка файлов, "прозрачное" закачка файлов, "прозрачное" программирование программирование backend-backend-скриптовскриптов

Кроссбраузерность, закачка, Кроссбраузерность, закачка, отладкаотладка, , многомерные данные, многомерные данные, русский язык, ...русский язык, ...

Дмитрий Котеров,Дмитрий Котеров,архитектор и главный разработчик архитектор и главный разработчик MoiKrug.ruMoiKrug.ru компания Яндекскомпания Яндекс

[email protected]@koterov.ru

Page 2: Js Http Request   дмитрий котеров

www.rit2007.ru

Что такое Что такое Web 2.0Web 2.0??

• © O'Reilly Media, 2004• Браузер есть

платформа• Данные – движущая

сила сайта• Демократия среди

пользователей, рейтинги, голосования

• Модель социальной сети

• Динамическая загрузка данных (AJAX)

Page 3: Js Http Request   дмитрий котеров

www.rit2007.ru

AJAXAJAX: идеология или просто модное : идеология или просто модное слово?слово?

• Asynchronous JavaScript And XML

• Старое название – Remote Scripting

• Компоненты:– Frontend– Backend

Page 4: Js Http Request   дмитрий котеров

www.rit2007.ru

АсинхронностьАсинхронность

1. Запустить запрос к серверу

2. Продолжить работу

3. Когда придет ответ, запустить обработчик

4. Обработать данные, изменить страницу

• Сложность AJAX-валидаторов• Событийно-ориентированное

программирование

Page 5: Js Http Request   дмитрий котеров

www.rit2007.ru

Методы динамической загрузкиМетоды динамической загрузки

• XMLHttpRequest

• ActiveX

• <script>

• невидимый <iframe>

• <img> + cookies

• кто-нибудь знает другие?

Page 6: Js Http Request   дмитрий котеров

www.rit2007.ru

XMLHttpRequestXMLHttpRequest

• Многословный интерфейс• Не работает в 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");

Page 7: Js Http Request   дмитрий котеров

www.rit2007.ru

XMLHttpRequest: XMLHttpRequest: обработка обработка XMLXML

<?phpheader('Content-type: application/xml');echo '<?xml version="1.0" encoding="windows-1251"?>';echo '<root><time>' . date('r') . '</time></root>';?>

var xml = req.responseXML;var timeNode = xml.getElementsByTagName('time')[0];alert(timeNode.childNodes[0].nodeValue);

• Сложно формировать • Сложно разбирать• Неустойчивость к ошибкам в backend

Page 8: Js Http Request   дмитрий котеров

www.rit2007.ru

XMLHttpRequest: 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

• Все еще неустойчивость к ошибкам

Page 9: Js Http Request   дмитрий котеров

www.rit2007.ru

XMLHttpRequest: XMLHttpRequest: русские кодировкирусские кодировки

• JavaScript – полностью Unicode-язык• escape(): кодирование в UCS2BE:

%u1234%u5678– работает даже в очень старых браузерах– сильно увеличивает объем

• encodeUriComponent(): кодирование в UTF-8 с urlencode: %B2%A3– работает начиная с IE 5.5+

• Однобайтовых кодировок нет

Page 10: Js Http Request   дмитрий котеров

www.rit2007.ru

ActiveXActiveX

• Работает только в IE5, IE6

• Должны быть разрешены ActiveX

• В IE 5.0 иногда возникают проблемы с кодировками (в backend передаются "?")

Page 11: Js Http Request   дмитрий котеров

www.rit2007.ru

ActiveX ActiveX и и XMLHttpRequest: 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; }

Page 12: Js Http Request   дмитрий котеров

www.rit2007.ru

<script><script>

var script = document.createElement('script');script.src = 'script_backend.php?id=1&a=123';document.appendChild(script);

<?php

$id = $_GET['id'];

$a = $_GET['a'];

$json = json_encode(process($a));

?>

dataReady({

id: "<?=$id?>",

data: <?=$json?>

});

Page 13: Js Http Request   дмитрий котеров

www.rit2007.ru

<script>: <script>: проблемыпроблемы

• Поддерживается только GET• Нельзя передать много данных• Нужно явно передавать ID• Opera: загрузка <script> - блокирующая

(синхронная) операция• Opera: только

div.innerHTML = 'text<script></script>'• В некоторых браузерах не работает

вообще (например, Opera 7.10)

Page 14: Js Http Request   дмитрий котеров

www.rit2007.ru

<iframe><iframe>

var iframe = document.createElement('iframe');iframe.name = 'dyna';document.appendChild(iframe);form.target = iframe.name;form.submit();

<?php

$id = $_GET['id'];

$a = $_GET['a'];

$json = json_encode(process($a));

?>

<script>

dataReady({

id: "<?=$id?>",

data: <?=$json?>

});

</script>

Page 15: Js Http Request   дмитрий котеров

www.rit2007.ru

<iframe>:<iframe>: плюсы и минусы плюсы и минусы

• Плюсы– нет проблем с русскими кодировками– отправка формы целиком– поддержка методов GET и POST– можно закачивать файлы

• element.cloneNode() не работает в Safari для файловых полей

• Минусы– щелчок– засорение history– баги в FF с кнопкой Назад– большой расход памяти– плохая кроссбраузерность

Page 16: Js Http Request   дмитрий котеров

www.rit2007.ru

<img> + cookies<img> + cookies

var img = document.createElement('img');img.src = 'img_backend.php?id=1&a=123';img.onload = function () { alert(document.cookies);}document.appendChild(img);

<?php$data = process();setcookie('result', json_encode($data), '/');?>

• Исключительно высокая кроссбраузерность!• Но: должны быть включены cookies

Page 17: Js Http Request   дмитрий котеров

www.rit2007.ru

Обзор всех методовОбзор всех методов: : проблемыпроблемы

• Совершенно разные интерфейсы

• Трудно передавать сложные данные:{ some: value, other: { key: value } }

• Трудно принимать сложные данные

• Разные методы для разных браузеров

• Русскоязычные кодировки

• Обработка ошибок в backend

Page 18: Js Http Request   дмитрий котеров

www.rit2007.ru

Есть ли решение?Есть ли решение?

• ДА!

• JsHttpRequest решает все перечисленные проблемы

Page 19: Js Http Request   дмитрий котеров

www.rit2007.ru

Упрощенный интерфейс вызоваУпрощенный интерфейс вызова

// Frontend: JavaScriptJsHttpRequest.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-а)

Page 20: Js Http Request   дмитрий котеров

www.rit2007.ru

ПримерПример: suggest (frontend): suggest (frontend) JsHttpRequest.query( // Адрес backend-сценария. 'suggest_backend.php', // Так передаются параметры backend-у { 'str': st, // первые буквы слова 'num': 10 // число элементов списка для вывода }, // Функция вызывается, когда backend подготовил данные. function(result, errors) { // Записать сообщения об ошибках в <div>. 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 );

Page 21: Js Http Request   дмитрий котеров

www.rit2007.ru

ПримерПример: suggest (backend): suggest (backend)<?php// Загрузить библиотеку JsHttpRequest.require_once "JsHttpRequest/JsHttpRequest.php";// Инициализация. Обязательно указывайте кодировку сценария!$JsHttpRequest =& new JsHttpRequest("windows-1251");

// Получить запрос: первые буквы слова и число элементов.$str = $_REQUEST['str'];$num = $_REQUEST['num'];...

// Передать результат поиска во frontend.global $_RESULT;$_RESULT = array( "str" => $str, "list" => $found,);

// Выводим также отладочную информацию.echo sprintf("Выборка %d из %d слов.", count($found), count($words));?>

Page 22: Js Http Request   дмитрий котеров

www.rit2007.ru

Закачка файлов "Закачка файлов "AJAX-AJAX-ом"ом"

• Проблема безопасности

• Библиотеке передается не файл, а элемент выбора файла

• Проблема в Safari: <input type="file"> нельзя клонировать и перемещать в другую форму

Page 23: Js Http Request   дмитрий котеров

www.rit2007.ru

Закачка файлов "Закачка файлов "AJAX-AJAX-ом"ом"<form enctype="multipart/form-data"> <input type="file" name="e_file" id="e_file"></form>...JsHttpRequest.query( 'backend.php', { 'str': { nested: st }, 'upl': document.getElementById('e_file') }, function(result, errors) { ... });

<?php...$str = $_REQUEST['str']['nested'];

// Работаем с $_FILES, как обычно!// Элемент в $_FILES приходит с именем "upl", а не "e_file".$tmpName = $_FILES['upl'];?>

Page 24: Js Http Request   дмитрий котеров

www.rit2007.ru

Отправка формы целикомОтправка формы целиком

<form enctype="multipart/form-data" id="e_form"> <input type="file" name="e_file"> <input type="text" name="str"></form>...JsHttpRequest.query( 'backend.php', document.getElementById('e_form') function(result, errors) { ... });

<?php...$str = $_REQUEST['str'];

// Работаем с $_FILES, как обычно!// Имена элементов а $_REQUEST и $_FILES совпадают с // именами полей формы.$tmpName = $_FILES['e_file'];?>

Page 25: Js Http Request   дмитрий котеров

www.rit2007.ru

Русскоязычные кодировкиРусскоязычные кодировки

• Работа с кодировками полностью прозрачна как для frontend, так и для backend

• JsHttpRequest может работать с windows-1251 и koi8-r и при отсутствии iconv (собственные таблицы)

• Для ускорения в PHP 5.2 автоматически используется json_encode()

Page 26: Js Http Request   дмитрий котеров

www.rit2007.ru

СессииСессии

• Работа с сессиями полностью прозрачна и происходит стандартными средствами PHP

Page 27: Js Http Request   дмитрий котеров

www.rit2007.ru

Выбор метода и загрузчикаВыбор метода и загрузчика

JsHttpRequest.query( 'GET backend.php', ...);

JsHttpRequest.query( 'xml.POST backend.php', ...);

JsHttpRequest.query( 'http://other.host.ru/backend.php', ...);

• По умолчанию выбирается наилучший загрузчик и метод, совместимые с браузером

• Возможна загрузка с "чужого" домена (script, form)

Page 28: Js Http Request   дмитрий котеров

www.rit2007.ru

КэшированиеКэширование

• Четвертый параметр JsHttpRequest.query().

• Если кэширование включено, то при попытке повторной загрузки по тому же самому запросу данные берутся из кэша.

• Не работает для закачки файлов, а также для отправки формы целиком.

Page 29: Js Http Request   дмитрий котеров

www.rit2007.ru

Отладка и перехват ошибок Отладка и перехват ошибок в в backendbackend

<?phprequire_once "JsHttpRequest/JsHttpRequest.php";$JsHttpRequest =& new JsHttpRequest("windows-1251");...ini_set('display_errors', true);call_to_undefined_function();?>

JsHttpRequest.query( 'backend.php', { ... }, function(result, errors) { if (errors) alert(errors); });

• Кто сказал, что фатальные ошибкиPHP нельзя перехватить?

Page 30: Js Http Request   дмитрий котеров

www.rit2007.ru

Отладка и перехват ошибок Отладка и перехват ошибок в в backendbackend

• Пример данных, сгенерированных backend-ом

JsHttpRequest.dataReady({ "id": "123", "js": { "str": "строка", ... }, "text": "Сообщения и ошибки."})

Page 31: Js Http Request   дмитрий котеров

www.rit2007.ru

Ошибки во Ошибки во frontendfrontend

• Все ошибки генерируются в виде исключений JavaScript: throw new Error(...)

1. 'Invalid FORM element detected: name=%, tag=%',2. 'If used, <form> 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.'

Page 32: Js Http Request   дмитрий котеров

www.rit2007.ru

Интерфейс, совместимый с Интерфейс, совместимый с XMLHttpRequestXMLHttpRequest

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

• Легкая миграция существующих приложений

Page 33: Js Http Request   дмитрий котеров

www.rit2007.ru

Модульная архитектураМодульная архитектура

• Код библиотеки состоит из частей:– Базовый модуль (неотключаемый)– Модуль поддержки XML– Модуль поддержки script– Модуль поддержки form

• Любой модуль можно удалить из кода даже "вручную"• mini/JsHttpRequest-script.js: только загрузчик script (8.2К)• mini/JsHttpRequest-script-xml.js: только script и xml• debug/*.js: полные версии исходников с комментариями• mini/*.js: "минимизированные" версии (dojomin)• "Минимизированная" версия со всеми загрузчиками: 14К

Page 34: Js Http Request   дмитрий котеров

www.rit2007.ru

Обеспечение кроссбраузерностиОбеспечение кроссбраузерности

• Автоматизированный test framework

• На каждый багфикс – один тест

• На каждую сгенерированную ошибку – один тест

• Главная сложность при тестировании – принципиальная асинхронность

Page 35: Js Http Request   дмитрий котеров

www.rit2007.ru

Backend-Backend-ы на неы на не-PHP-PHP

• За время существования библиотеки зарегистрированы случаи создания умельцами backend-модулей на:– perl– c– parser

• К сожалению, все они не дотягивают до production-версий

• Но никаких препятствий нет!

Page 36: Js Http Request   дмитрий котеров

www.rit2007.ru

РезюмеРезюме

• Кроссбраузерность (IE5.0+ без ActiveX, Mozilla 1.7+, Firefox 1.0+, Opera 7.20+, Safari)

• Прозрачная работа с русскими кодировками• Закачка файлов методом AJAX• Поддержка отладочных возможностей PHP• Двусторонняя передача многомерных структур

PHP <-> JavaScript• Поддержка сессий PHP• Выбор оптимального загрузчика• Компонентность• Совместимый с XMLHttpRequest интерфейс

Page 37: Js Http Request   дмитрий котеров

www.rit2007.ru

Приходите к нам работать!Приходите к нам работать!

• МойКруг.ру теперь – сервис Яндекса• Мы расширяем свою команду!• Открыты вакансии для:

– верстальщиков со знанием Smarty– отличных PHP-программистов

Ждем Ваши резюме на http://moikrug.ru/hire/