Мастер-классы по Javascript, AJAX/COMET, jQuery Узнать больше...
Javascript.RU

Обмен данными между доменами. Часть 2.

Эта статья является продолжением статьи Обмен данными для документов с разных доменов и рассматривает новые способы обмена данными между доменами, которые, однако, уже поддерживаются основными современными браузерами.

В стандарте HTML5 предусмотрена отсылка javascript-сообщения из одного окна в другое при помощи специального вызова window.postMessage.

При этом окна могут быть с любых доменов, не важно. Например, один iframe с yandex.ru , а другой - с vaysapupkin.info. Чтобы получать кросс-доменные сообщения, принимающее окно регистрирует специальный обработчик onmessage, в котором, кроме всего прочего, может проверить, с какого домена пришло сообщение.

В примере ниже используется iframe с домена javascript.ru, исходник которого приведен ниже, и iframe с домена ilyakantor.ru.

Как вы можете видеть, сообщение прекрасно пересылается. Пример работает в браузерах Firefox 3.5, Opera 10, Safari 4.0/Chrome 3.0+, Internet Explorer 8.0.

Исходник окна, отправляющего сообщение:

<html>
<body>
<iframe src="http://ilyakantor.ru/receive.html" id="iframe"></iframe>
<form id="form">
  <input type="text" id="msg" value="Ваше сообщение"/>
  <input type="submit"/>
</form>
<script>
var win = document.getElementById("iframe").contentWindow;

document.getElementById("form").onsubmit = function(){
	win.postMessage(
		document.getElementById("msg").value,
		"http://ilyakantor.ru" // target domain
	);
	return false
}
</script>
</body>
</html>

Как видите, для передачи сообщения достаточно вызвать метод postMessage(message, targetOrigin) принимающего окна.

message
Сообщение - javascript-объект
targetOrigin
Целевой домен, с которого должно быть окно, получающее сообщение. Если вы не хотите ограничить целевой домен - поставьте вместо него звездочку "*".

Исходный код принимающего окна (в ифрейме):

<html>
<body>
<b>iframe с домена http://ilyakantor.ru</b>
<div id="test">Пришли мне сообщение!</div>
<script>
function listener(event){
	if ( event.origin !== "http://javascript.ru" )
		return;

	document.getElementById("test").innerHTML = event.origin + " прислал: " + event.data;
}

if (window.addEventListener){
	window.addEventListener("message", listener,false);
} else {
	window.attachEvent("onmessage", listener);
}


</script>

</body>
</html>

Обработчик события onmessage проверяет исходный домен, который находится в свойстве event.origin, и, если все нормально, выводит на экран сообщение event.data.

Все прозрачно и удобно.

Реализация postMessage браузерами использует внутренний механизм передачи сообщений, поэтому можно передавать любые объекты, а сам факт передачи никак не отслеживается снифферами пакетов.

Интерфейс поддерживается основными современными браузерами.

Уже давно в W3C вызревает второй стандарт XMLHTTPRequest 2. А пока суть да дело - Firefox 3.5, Safari 4/Chrome 3 и IE8 уже реализовали ряд фич.

Например, кросс-доменные запросы.

Следующий пример отправляет запрос с текущего домена (javascript.ru) на домен ilyakantor.ru.

Он не работает в старых браузерах и... в Opera.

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

Сервер в ответе указывает заголовком Access-Control-Allow-Origin, для каких доменов доступны данные. Ответ сервера:

Если вдруг домен, на который приходит ответ, не совпадает с Access-Control-Allow-Origin (можно указать звездочку "*" для любого домена), то браузер блокирует операцию из соображений безопасности.

В то время как Firefox/Safari расширили обычный объект XMLHTTPRequest, специалисты Microsoft завели для кросс-доменных запросов новый объект XDomainRequest.

Оба объекта имеют весьма схожие интерфейсы, но решение Firefox/Safari более полно реализует XMLHTTPRequest 2. В частности, поддерживаются другие методы, кроме GET/POST, работа с Cookie/HTTP Auth и расширены средства контроля доступа.

Исходный код отсылающего запрос ифрейма:

<html>
<head>

<script type="text/javascript">
    var url = 'http://ilyakantor.ru/xdr/receive.php';

    function doCallOtherDomain(){
        var XHR = window.XDomainRequest || window.XMLHttpRequest
        var xhr = new XHR();

        xhr.open('GET', url, true);

        // замена onreadystatechange
        xhr.onload = function() {
            document.getElementById('response').innerHTML = xhr.responseText
        }

        xhr.onerror = function() {
            alert("Error")
        }

        xhr.send()
    }

    function callOtherDomain() {
        try {
            doCallOtherDomain()
        } catch (e) {
            alert("В этом браузере данная фича не поддерживается.")
        }
    }

    </script>
</head>
<body>

<div id="response"></div>
    <input type="button" value="Нажмите для запроса к другому домену" onclick="callOtherDomain()" />

</body>
</html>

Принимающий код:

<?php
// можно ограничить домен, для которого доступен ответ
// header('Access-Control-Allow-Origin: http://javascript.ru');

header('Access-Control-Allow-Origin: *');
?>
http://ilyakantor.ru Ха-ха! Все получилось!

Как видно из примера, в обоих реализациях можно отказаться от onreadystatechange и использовать события onload/onerror/onabort.

Кроме того, начиная с Firefox 3.5/Safari 4/IE8 поддерживается событие onprogress, предназначенное для реализации progress bar.

Конечно, можно написать кросс-браузерную обертку, которая будет прозрачно отправлять запросы, используя эти новые методы в дополнение к уже существующим.

Мы разобрали основы новых способов кросс-доменной коммуникации. При практической реализации вам могут понадобиться детали.

Могу порекомендовать следующие статьи.


Автор: Гость (не зарегистрирован), дата: 12 ноября, 2009 - 14:45
#permalink

то есть получается, что с помощью этой фичи можно xss атаки проводить еще проще... например, передать куки с одного домена ну другой ?


Автор: subzey, дата: 20 ноября, 2009 - 12:40
#permalink

Если скрипт будет отдавать что попало кому попало, то да.


Автор: viglim (не зарегистрирован), дата: 5 февраля, 2010 - 15:01
#permalink

Именно этим разработчики оперы мотивируют категорическое нежелание делать возможность обычных кросс-браузерных запросов.


Автор: Гость (не зарегистрирован), дата: 10 апреля, 2010 - 00:03
#permalink

Гость что отпостил выше и viglim:

вы как бы не заметили строчку про то, что сервер к которому делается кросс запрос (уточнение идет даже относительно скрипта на серваке) должен разрешать делать к себе запросы, причем кого то может игнорировать.

поэтому уже безопасность будет зависить от прямоты рук тех, кто использует данный заголовок.


Автор: Зайва Игорь Леонидович (не зарегистрирован), дата: 21 июля, 2010 - 10:17
#permalink

Прикольно полдня просидел в поисках решения передачи запроса с одного своего сайта на другой и вуаля... Автору спасибо. От себя замечу: простой скриптик всего в несколько строчек работает на Мозиле (3.6) у меня без всяких выкрутасов (в других браузерах пока не проверял), всё, что здесь написано - не заработало у меня, хотя примеры на этой странице работают, как и написано. Эх, лень копаться в глюках.

Для передачи параметров на другой сайт всего лишь прописал строку, указанную в статье и всё:

header('Access-Control-Allow-Origin: *');


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
11 + 2 =
Введите результат. Например, для 1+3, введите 4.
 
Новости

Открылась регистрация на мастер-классы по профессиональному Javascript, AJAX/COMET, jQuery в городах:

  • Ярославль (24-25 сентября)
  • Новосибирск (3-4 октября)
  • Казань (9-10 октября)
  • Минск (16-17 октября)
  • Днепропетровск (23-24 октября)
  • Одесса (30-31 октября)
  • Самара (13-14 ноября)

Более подробно - на странице мастер-классов.

Если вас интересует другой город - посмотрите здесь, выбрав "Другие города".

Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Статьи и мероприятия

Будьте в курсе наших последних новостей!

Последние обсуждения на форуме
Forum
Последние комментарии