Javascript.RU

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

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/xhr-crossdomain.

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

В стандарте 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 - 13:45
#permalink

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


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

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


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

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


Автор: Гость (не зарегистрирован), дата: 22 июня, 2012 - 16:16
#permalink

Кросс-доменные запросы


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

Ты хотел сказать кроссайтовые т.е. крос доменные a.com b.com


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

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

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

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


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

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

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

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


Автор: matfor2013, дата: 7 декабря, 2013 - 22:49
#permalink

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

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

А куда прописал? У меня похожая ситуация, получаю от сервера Origin "null" и пустой ответ. Подскажите.


Автор: Snipe, дата: 13 ноября, 2010 - 17:55
#permalink

ИЕ 7 и ИЕ 6 еще долго будут портить кровь программистам, не давая возможности использовать эти фишки, а это чуть больше 10% по статистики li


Автор: Armen, дата: 28 февраля, 2011 - 15:35
#permalink

То есть таким способом, можно читать xml файлы с других доменов ?


Автор: Boo (не зарегистрирован), дата: 2 мая, 2011 - 23:11
#permalink

XMLHTTPRequest 2 если не ошибаюсь, если делает запрос на другой домен, перед этим сначало запрашивает ту же страницу с методом OPTION. а уже потом идет запрос либо GET либо POST либо что то еще.


Автор: Гость (не зарегистрирован), дата: 6 марта, 2012 - 15:57
#permalink

Здесь, при нажатии Отправить, сообщение посылается во фрейм. Если добавить второй фрейм с каким-либо сайтом, как послать в первый фрейм вместо сообщения адрес из второго фрейма?


Автор: Tester1199357 (не зарегистрирован), дата: 28 марта, 2012 - 15:41
#permalink

С локального файла не работает - надо обязательно загрузить на реальный сервер
То есть убогий костыль!

Интересно что через яховский прокси работает отвосюду в том числе и с локального файла.


Автор: Sanya_Zol, дата: 23 июня, 2012 - 00:55
#permalink

XMLHTTPRequest 2 / XDomainRequest
В недавно вышедшей опере 12.00 сделали


Автор: Гость (не зарегистрирован), дата: 5 июля, 2012 - 00:52
#permalink

подскажите пожалуйста очень нужно. А как правильно формировать обращение к окну, если нам надо наоборот отправить обращение из ифрейма к перент окну? или как правильно обратиться к не вложенному, а соседнему ифрейму? (вопрос по способу postMessage)


Автор: Vovumba, дата: 20 июля, 2012 - 13:03
#permalink

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

Но лучше не изобретать велосипеды, а использовать библиотеку типа easyXDM (так же есть плагин для jQuery для работы с postMessage). Там все это реализовано довольно удобно, в том числе механизм удаленного вызова процедур, который является надстройкой над вот таким транспортом (или другим, если браузер не поддерживает его).


Автор: Гость (не зарегистрирован), дата: 10 октября, 2013 - 17:25
#permalink

Ребят... Curl вам в помощь... Отправляете запрос на php на своем домене, Curl отправляет запрос на другой и возвращает ответ Вам... Если бы опера еще работала с этим, то было бы норм. А так через фреймы или отправлять Ajaxом. Ну нафиг. На php это 5 строчек и полная кроссбраузерность))


Автор: SkyLight, дата: 11 октября, 2013 - 12:35
#permalink

Это далеко не всегда и не всем подходит. Иногда нужно использовать именно клиентский вариант.


Автор: Гость: Ермолаев Андрей (не зарегистрирован), дата: 12 августа, 2016 - 04:25
#permalink

Curl, wget и любые другие серверные качалки для разовых задач, при этом нагрузка на сервер, что облегчается и ускоряется Ajax-ом.


Автор: Гость (не зарегистрирован), дата: 28 января, 2014 - 16:53
#permalink

Помогите, пожалуйста, разобраться с такой вот проблемой.
Делается кроссдоменный POST-запрос по отправке файла, в ответе идет строка с идентификатором добавленного объекта (Content-type: text/plain).
Все браузеры адекватно эту строку вынимают при помощи xhr.responseText, а вот у IE10 в xhr.responseText всегда пусто.
Что там может быть такое?


Автор: Гость (не зарегистрирован), дата: 19 мая, 2014 - 10:07
#permalink

IE11, FR29.0.1
В этом браузере данная фича не поддерживается.

CR34.0
Всё ok


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

Учебник javascript

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

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

Интерфейсы

Все об AJAX

Оптимизация

Разное

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

Последние темы на форуме
Forum