Транспорт, ajax

Михаил Давыдов
Разработчик JavaScript
Немного истории

•  FRAME, IFRAME – IE 3, 1996год
•  ActiveX MSXML – IE 5.5, 1998год
•  AJAX, Web 2.0 – 2005год
•  W3C XMLHttpRequest – 2006год стандарт

3
Кроссодоменные запросы
JSONP,
Post2HiddenIframe,
XMLHttpRequest level 2 (CORS),
Каскад фреймов или postMessage
JSONP
0+

0+

0+

0+

•  Когда применять
–  Запрос каких-то не очень критичных данных
–  Прием огромных объемов данных

•  Плюсы
–  Дешевый способ
–  Доступен в любом браузере

•  Минусы
–  Невозможно отследить статус ответа и ошибки, только таймауты
–  Только GET
–  Не безопасный

5

3+
JSONP
// 1 Готовим «Ловушку»
window.jsonFlickrFeed = function (data) {
console.log(data);
};
var serviceUrl = 'http://api.flickr.com/services/feeds' +
'/photos_public.gne?format=json&' +
'jsoncallback=jsonFlickrFeed';
// 2 Создаем скрипт
var scriptElement = document.createElement('script');
scriptElement.src = serviceUrl;
document.body.appendChild(scriptElement);

http://jsfiddle.net/ffTQL/1/
Post2HiddenIframe
0+

0+

0+

•  Кода применять
–  Push каких-то не критичных данных
–  Отправка файлов

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

•  Минусы
–  Нет возможности подтвердить получение данных сервером

7

0+

3+
Post2HiddenIframe
// 1 Создаем форму
<form target="frame"
action="http://yandex.ru/"
method="post">
<input name="data"/>
<input type="submit"/>
</form>
// 2 Создаем фрейм
<iframe name="frame"></iframe>

http://jsfiddle.net/E2nge/
XHR2 (CORS)
4.0

•  Кода применять
–  Запрос критичных данных
–  Long Polling

•  Плюсы
–  Не отличается от XHR (IE – XDomainRequest)
–  Это не костыль
–  Можно отследить ошибки и статусы ответа
–  Простая реализация поддержки на сервере
–  DELETE, GET, HEAD, OPTIONS, POST, PUT

•  Минусы
–  Не поддерживается многими старыми браузерами
–  Может блокироваться прокси-серверами

9

3.5

12

4.0

10
XHR2 (CORS)
function requestFactory() {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
return xhr;
}
if (typeof XDomainRequest !== "undefined") {
return new XDomainRequest();
}
}
var xhr = requestFactory();
if (!xhr) throw new Error('CORS not supported');
xhr.open('GET', 'http://yandex.ru/', true);
xhr.send();

http://jsfiddle.net/qyjnb/
Каскад фреймов или postMessage

•  На самоподготовку
–  Выделите его достоинства и недостатки
–  Сравните с предыдущими методами

11
Real-time приложения
LongPolling через XHR,
EventSource (Server Sent Events),
WebSocket
WebRTC
LongPolling & XHR
1.0

0.6

8.0

1.2

•  Когда применять
–  Для обратной совместимости со старыми браузерами
–  Приложения где данные передаются редко
–  Вам лень писать что-то другое

•  Плюсы
–  Это работает во всех браузерах
–  Самая простая реализация

•  Минусы
–  Приходится постоянно создавать соединения
–  Для отправки данных необходимо поднимать еще одно соединение
–  Проблема с одновременными запросами

13

5.0
LongPolling & XHR
function poll(resource, callback) {
$.get(resource, function (e, data) {
if (callback(data)) {
poll(resource, callback);
}
});
}
poll('/echo/json/', function (data) {
console.log(data);
return Math.random() > 0.5;
});

http://jsfiddle.net/mtP2W/
EventSource
6.0

6.0

9.0

5.0

•  Когда применять
–  Ваш сервис большую часть времени получает данные
–  Для обратной совместимости со старыми браузерами

•  Плюсы
–  Использует HTTP протокол
–  Реализация на сервере достаточна проста
–  Может автоматически делать реконнект
–  Достаточно гибкий формат сообщений
–  1 постоянное соединение с сервером

•  Минусы
–  Может неадекватно вести себя при физическом отключении от сети
–  Может только принимать данные
–  Не поддерживается IE
–  Может блокироваться прокси-серверами
15

–
LongPolling & XHR
// Content-Type: text/event-stream
// Cache-Control: no-cache
if (!window.EventSource) throw new Error('No SSE');
var dataProvider = new EventSource('/echo/json/');
dataProvider.addEventListener('message', function(e) {
console.log(e.data);
}, false);
dataProvider.addEventListener('error', function(e) {
if (e.readyState == EventSource.CLOSED) {
console.log('Connection closed');
}
}, false);

http://jsfiddle.net/BvTTz/
WebSocket
14.0

11.0*

8.0

•  Когда применять
–  Актуальность данных очень критична
–  Очень много данных передается или передаются очень часто

•  Плюсы
–  1 соединение на отправку и получение
–  Быстрый обмен данными
–  Бинарный формат

•  Минусы
–  Не HTTP
–  Сложно отлаживать
–  Может блокироваться прокси-серверами
–  6 форматов протокола
–  Поддерживается далеко не всеми веб-браузерами
17

6.0

10.0
LongPolling & XHR
window.WebSocket = window.WebSocket || window.MozWebSocket;
var connection = new WebSocket('ws://echo.websocket.org');
connection.addEventListener('message', console.log, false);
connection.addEventListener('error', console.log, false);
connection.send('Hello World!');

http://jsfiddle.net/pgLQa/2/
WebRTC
28

•  getUserMedia, MediaStream
–  Захват потока с устройств: звук, экран, камера

•  RTCPeerConnection
–  Передача медиа-потоков

•  RTCDataChannel
–  Передача файлов

•  Session Description Protocol

19

22

16

–

–
WebRTC Как работает соединение

A	
  
20

B	
  
WebRTC Как работает соединение

A	
  

B	
  
NAT	


21
WebRTC Как работает соединение

A	
  
sdp	
  
22

B	
  
sdp	
  

NAT
WebRTC Как работает соединение

A	
  
sdp	
  
23

B	
  
sdp	
  

NAT
WebRTC Как работает соединение

sdp	
  

A	
  
sdp	
  
24

B	
  
sdp	
  

NAT
WebRTC Как работает соединение

sdp	
  

sdp	
  

A	
  
sdp	
  
25

B	
  
sdp	
  

NAT
WebRTC Как работает соединение

A	
  
sdp	
  
26

B	
  
sdp	
  
WebRTC
28

•  Когда применять
–  P2P сервисы: передача файлов
–  Видео конференции
–  Игры без монетизации

•  Плюсы
–  Дешевая поддержка
–  Простая реализация сигнального сервера
–  Любой протокол передачи hand-shake
–  Защищенный

•  Минусы
–  Поддерживается далеко не всеми веб-браузерами

27

22

16

–

–
WebRTC Запрос на соединение
var media = {audio: true, video: true};
navigator.getUserMedia(media, function (stream) {
var pc = new RTCPeerConnection();
pc.addStream(stream);
pc.createOffer(function (desc) {
pc.setLocalDescription(desc);
// Session Description Protocol
console.log(desc.sdp);
}, console.error);
}, console.error);

http://jsfiddle.net/tc9sy/
Загрузка файлов
Post2HiddenIframe + JSONP,
XMLHttpRequest level 2 + File API,
Flash
Post2HiddenIframe + JSONP
0+

0+

•  Post2HiddenIframe – для отправки
•  JSONP – для контроля
–  Прогресс отправки
–  Результат отправки
–  Получение ссылки на файл

•  Плюсы
–  Работает везде

•  Минусы
–  Необходим контроль
–  Много дополнительных запросов

30

0+

0+

3+
Post2HiddenIframe + JSONP
<form target="frame"
action="http://yandex.ru/"
method="post"
enctype="multipart/form-data">
<input name="file" type="file"/>
</form>
<iframe name="frame"></iframe>
$('input').change(function () {
$('form').submit();
});
$.getJSON('/echo/jsonp/?callback=?', function(e, progress) {
console.log(progress);
});

http://jsfiddle.net/AZmXx/2/
XHR2 + File API
13.0

3.6

12

5.1*

•  Плюсы
–  Естественный способ без костылей
–  Только 1 запрос
–  Реализация на сервере проще чем Post2HiddenIframe + JSONP

•  Минусы
–  Не поддерживается всеми браузерами

32

10.0*
XHR2 + File API
document.getElementById('file')
.addEventListener('change', function (e) {
var file = this.files[0];
var xhr = new XMLHttpRequest();
var formData = new FormData();
formData.append('thefile', file);
xhr.open('post', '/echo/json/', true);
xhr.setRequestHeader('Content-Type',
'multipart/form-data');
xhr.send(formData);
}, false);

http://jsfiddle.net/qnvt2/1/
Flash

•  На самоподготовку
–  Выделите его проблемы
–  Сравните с рассмотренными выше способами

34
Библиотеки и обертки
jQuery.ajax,
jQuery.serialize,
Socket.IO,
NowJS
jQuery.ajax
var globalCallback = function () {
console.log(arguments);
};
$.get('/echo/json/', globalCallback);
$.post('/echo/json/', globalCallback);
$.getJSON('/echo/json/', globalCallback);
$.getJSON('/echo/jsonp/?callback=?', globalCallback);
$.ajax('/echo/json/', {
statusCode: {
404: globalCallback
}
}).done(globalCallback);

http://jsfiddle.net/hLU92/
jQuery.serialize
<form>
<input type="text" name="a" value="1"/>
<input type="text" name="b" value="2"/>
<input type="hidden" name="c" value="3"/>
</form>

$('form').submit(function() {
alert($(this).serialize());
return false;
});

http://jsfiddle.net/Smvvr/
Socket.IO
var io = require('socket.io').listen(80);
// Server
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});

var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});

http://socket.io/
NowJS
var nowjs = require("now");
var everyone = nowjs.initialize(httpServer);

// Server

everyone.now.getServerInfo = function(callback){
callback("Hello World!");
}

<script src="//localhost/nowjs/now.js"></script>
<script>
now.getServerInfo(function(data){
console.log(data);
});
</script>

http://nowjs.com/
Проблемы
Проблемы
•  Каскады протоколов
–  Дорогая поддержка

•  Баги браузеров
–  Повторный запрос после abort() зависает
–  N соединений с доменом на браузер/таб

•  Прокси серверы
–  Кэширование
–  Игнорирование "странных" протоколов и заголовков

•  Обрывы соединения
–  Спасает только ping

•  Асинхронная модель приложения
41
Михаил Давыдов
Разработчик JavaScript

azproduction@yandex-team.ru
azproduction

Спасибо

Михаил Давыдов: Транспорт, ajax

  • 2.
  • 3.
    Немного истории •  FRAME,IFRAME – IE 3, 1996год •  ActiveX MSXML – IE 5.5, 1998год •  AJAX, Web 2.0 – 2005год •  W3C XMLHttpRequest – 2006год стандарт 3
  • 4.
  • 5.
    JSONP 0+ 0+ 0+ 0+ •  Когда применять – Запрос каких-то не очень критичных данных –  Прием огромных объемов данных •  Плюсы –  Дешевый способ –  Доступен в любом браузере •  Минусы –  Невозможно отследить статус ответа и ошибки, только таймауты –  Только GET –  Не безопасный 5 3+
  • 6.
    JSONP // 1 Готовим«Ловушку» window.jsonFlickrFeed = function (data) { console.log(data); }; var serviceUrl = 'http://api.flickr.com/services/feeds' + '/photos_public.gne?format=json&amp;' + 'jsoncallback=jsonFlickrFeed'; // 2 Создаем скрипт var scriptElement = document.createElement('script'); scriptElement.src = serviceUrl; document.body.appendChild(scriptElement); http://jsfiddle.net/ffTQL/1/
  • 7.
    Post2HiddenIframe 0+ 0+ 0+ •  Кода применять – Push каких-то не критичных данных –  Отправка файлов •  Плюсы –  Реализация очень проста –  Доступен в любом браузере –  Можно отправлять файлы –  POST, GET •  Минусы –  Нет возможности подтвердить получение данных сервером 7 0+ 3+
  • 8.
    Post2HiddenIframe // 1 Создаемформу <form target="frame" action="http://yandex.ru/" method="post"> <input name="data"/> <input type="submit"/> </form> // 2 Создаем фрейм <iframe name="frame"></iframe> http://jsfiddle.net/E2nge/
  • 9.
    XHR2 (CORS) 4.0 •  Кодаприменять –  Запрос критичных данных –  Long Polling •  Плюсы –  Не отличается от XHR (IE – XDomainRequest) –  Это не костыль –  Можно отследить ошибки и статусы ответа –  Простая реализация поддержки на сервере –  DELETE, GET, HEAD, OPTIONS, POST, PUT •  Минусы –  Не поддерживается многими старыми браузерами –  Может блокироваться прокси-серверами 9 3.5 12 4.0 10
  • 10.
    XHR2 (CORS) function requestFactory(){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { return xhr; } if (typeof XDomainRequest !== "undefined") { return new XDomainRequest(); } } var xhr = requestFactory(); if (!xhr) throw new Error('CORS not supported'); xhr.open('GET', 'http://yandex.ru/', true); xhr.send(); http://jsfiddle.net/qyjnb/
  • 11.
    Каскад фреймов илиpostMessage •  На самоподготовку –  Выделите его достоинства и недостатки –  Сравните с предыдущими методами 11
  • 12.
    Real-time приложения LongPolling черезXHR, EventSource (Server Sent Events), WebSocket WebRTC
  • 13.
    LongPolling & XHR 1.0 0.6 8.0 1.2 • Когда применять –  Для обратной совместимости со старыми браузерами –  Приложения где данные передаются редко –  Вам лень писать что-то другое •  Плюсы –  Это работает во всех браузерах –  Самая простая реализация •  Минусы –  Приходится постоянно создавать соединения –  Для отправки данных необходимо поднимать еще одно соединение –  Проблема с одновременными запросами 13 5.0
  • 14.
    LongPolling & XHR functionpoll(resource, callback) { $.get(resource, function (e, data) { if (callback(data)) { poll(resource, callback); } }); } poll('/echo/json/', function (data) { console.log(data); return Math.random() > 0.5; }); http://jsfiddle.net/mtP2W/
  • 15.
    EventSource 6.0 6.0 9.0 5.0 •  Когда применять – Ваш сервис большую часть времени получает данные –  Для обратной совместимости со старыми браузерами •  Плюсы –  Использует HTTP протокол –  Реализация на сервере достаточна проста –  Может автоматически делать реконнект –  Достаточно гибкий формат сообщений –  1 постоянное соединение с сервером •  Минусы –  Может неадекватно вести себя при физическом отключении от сети –  Может только принимать данные –  Не поддерживается IE –  Может блокироваться прокси-серверами 15 –
  • 16.
    LongPolling & XHR //Content-Type: text/event-stream // Cache-Control: no-cache if (!window.EventSource) throw new Error('No SSE'); var dataProvider = new EventSource('/echo/json/'); dataProvider.addEventListener('message', function(e) { console.log(e.data); }, false); dataProvider.addEventListener('error', function(e) { if (e.readyState == EventSource.CLOSED) { console.log('Connection closed'); } }, false); http://jsfiddle.net/BvTTz/
  • 17.
    WebSocket 14.0 11.0* 8.0 •  Когда применять – Актуальность данных очень критична –  Очень много данных передается или передаются очень часто •  Плюсы –  1 соединение на отправку и получение –  Быстрый обмен данными –  Бинарный формат •  Минусы –  Не HTTP –  Сложно отлаживать –  Может блокироваться прокси-серверами –  6 форматов протокола –  Поддерживается далеко не всеми веб-браузерами 17 6.0 10.0
  • 18.
    LongPolling & XHR window.WebSocket= window.WebSocket || window.MozWebSocket; var connection = new WebSocket('ws://echo.websocket.org'); connection.addEventListener('message', console.log, false); connection.addEventListener('error', console.log, false); connection.send('Hello World!'); http://jsfiddle.net/pgLQa/2/
  • 19.
    WebRTC 28 •  getUserMedia, MediaStream – Захват потока с устройств: звук, экран, камера •  RTCPeerConnection –  Передача медиа-потоков •  RTCDataChannel –  Передача файлов •  Session Description Protocol 19 22 16 – –
  • 20.
    WebRTC Как работаетсоединение A   20 B  
  • 21.
    WebRTC Как работаетсоединение A   B   NAT 21
  • 22.
    WebRTC Как работаетсоединение A   sdp   22 B   sdp   NAT
  • 23.
    WebRTC Как работаетсоединение A   sdp   23 B   sdp   NAT
  • 24.
    WebRTC Как работаетсоединение sdp   A   sdp   24 B   sdp   NAT
  • 25.
    WebRTC Как работаетсоединение sdp   sdp   A   sdp   25 B   sdp   NAT
  • 26.
    WebRTC Как работаетсоединение A   sdp   26 B   sdp  
  • 27.
    WebRTC 28 •  Когда применять – P2P сервисы: передача файлов –  Видео конференции –  Игры без монетизации •  Плюсы –  Дешевая поддержка –  Простая реализация сигнального сервера –  Любой протокол передачи hand-shake –  Защищенный •  Минусы –  Поддерживается далеко не всеми веб-браузерами 27 22 16 – –
  • 28.
    WebRTC Запрос насоединение var media = {audio: true, video: true}; navigator.getUserMedia(media, function (stream) { var pc = new RTCPeerConnection(); pc.addStream(stream); pc.createOffer(function (desc) { pc.setLocalDescription(desc); // Session Description Protocol console.log(desc.sdp); }, console.error); }, console.error); http://jsfiddle.net/tc9sy/
  • 29.
    Загрузка файлов Post2HiddenIframe +JSONP, XMLHttpRequest level 2 + File API, Flash
  • 30.
    Post2HiddenIframe + JSONP 0+ 0+ • Post2HiddenIframe – для отправки •  JSONP – для контроля –  Прогресс отправки –  Результат отправки –  Получение ссылки на файл •  Плюсы –  Работает везде •  Минусы –  Необходим контроль –  Много дополнительных запросов 30 0+ 0+ 3+
  • 31.
    Post2HiddenIframe + JSONP <formtarget="frame" action="http://yandex.ru/" method="post" enctype="multipart/form-data"> <input name="file" type="file"/> </form> <iframe name="frame"></iframe> $('input').change(function () { $('form').submit(); }); $.getJSON('/echo/jsonp/?callback=?', function(e, progress) { console.log(progress); }); http://jsfiddle.net/AZmXx/2/
  • 32.
    XHR2 + FileAPI 13.0 3.6 12 5.1* •  Плюсы –  Естественный способ без костылей –  Только 1 запрос –  Реализация на сервере проще чем Post2HiddenIframe + JSONP •  Минусы –  Не поддерживается всеми браузерами 32 10.0*
  • 33.
    XHR2 + FileAPI document.getElementById('file') .addEventListener('change', function (e) { var file = this.files[0]; var xhr = new XMLHttpRequest(); var formData = new FormData(); formData.append('thefile', file); xhr.open('post', '/echo/json/', true); xhr.setRequestHeader('Content-Type', 'multipart/form-data'); xhr.send(formData); }, false); http://jsfiddle.net/qnvt2/1/
  • 34.
    Flash •  На самоподготовку – Выделите его проблемы –  Сравните с рассмотренными выше способами 34
  • 35.
  • 36.
    jQuery.ajax var globalCallback =function () { console.log(arguments); }; $.get('/echo/json/', globalCallback); $.post('/echo/json/', globalCallback); $.getJSON('/echo/json/', globalCallback); $.getJSON('/echo/jsonp/?callback=?', globalCallback); $.ajax('/echo/json/', { statusCode: { 404: globalCallback } }).done(globalCallback); http://jsfiddle.net/hLU92/
  • 37.
    jQuery.serialize <form> <input type="text" name="a"value="1"/> <input type="text" name="b" value="2"/> <input type="hidden" name="c" value="3"/> </form> $('form').submit(function() { alert($(this).serialize()); return false; }); http://jsfiddle.net/Smvvr/
  • 38.
    Socket.IO var io =require('socket.io').listen(80); // Server io.sockets.on('connection', function (socket) { socket.emit('news', { hello: 'world' }); socket.on('my other event', function (data) { console.log(data); }); }); var socket = io.connect('http://localhost'); socket.on('news', function (data) { console.log(data); socket.emit('my other event', { my: 'data' }); }); http://socket.io/
  • 39.
    NowJS var nowjs =require("now"); var everyone = nowjs.initialize(httpServer); // Server everyone.now.getServerInfo = function(callback){ callback("Hello World!"); } <script src="//localhost/nowjs/now.js"></script> <script> now.getServerInfo(function(data){ console.log(data); }); </script> http://nowjs.com/
  • 40.
  • 41.
    Проблемы •  Каскады протоколов – Дорогая поддержка •  Баги браузеров –  Повторный запрос после abort() зависает –  N соединений с доменом на браузер/таб •  Прокси серверы –  Кэширование –  Игнорирование "странных" протоколов и заголовков •  Обрывы соединения –  Спасает только ping •  Асинхронная модель приложения 41
  • 42.