То, как мы реализовали предыдущий пример, нельзя назвать передовой практикой, особенно с учетом необходимости обеспечения безопасности данных. Код в главном документе отправляет сообщение в определенный фрейм, но никак не контролирует то, каким документам позволено считывать это сообщение (данные сообщения смогут прочитать любые документы внутри iframe). Помимо этого код во фрейме iframe не проверяет источник и обрабатывает все полученные сообщения. Для того чтобы предотвратить злоупотребления такой реализацией, необходимо улучшить обе стороны коммуникационного процесса.
В следующем примере мы исправим ситуацию и продемонстрируем, как отвечать на сообщение из целевого документа, используя еще одно свойство события message — свойство source.
Листинг 13.17. Обмен сообщениями с конкретными источниками и целевыми документами
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Обмен сообщениями между документами</title>
<link rel="stylesheet" href="messaging. css">
<script src="messaging. js"></script>
</head>
<body>
<section id="formbox"> form name="form">
<p>Ваше имя: <input type="text" name="name" id="name" required></p>
<p><input type="button" name="button" id="button" value="Отправить"></p>
</form>
</section>
<section id="databox">
<iframe id="iframe" src="http://www.domain2.com/iframe.html" width="500" height="350"></iframe>
</section>
</body>
</html>
Предполагается, что новый HTML-документ с кодом из листинга 13.17 расположен в домене www.domain1.com. Однако если вы внимательно просмотрите код, то обнаружите, что фрейм iframe загружает файл из другого местоположения в домене www.domain2.com. Для предотвращения злоупотреблений эти два местоположения необходимо объявить в коде JavaScript, точно указав, каким документам разрешено читать сообщения и откуда эти сообщения могут быть отправлены.
В коде из листинга 13.17 мы не только указываем HTML-файл, являющийся источником фрейма, как уже делали раньше, — теперь мы объявляем полный путь к другому местоположению (Www. domain2.com). Таким образом, главный документ находится в домене Www. domain1.com, а содержимое iframe — в домене www.domain2.com. В следующих примерах кода это условие принимается во внимание.
Function initiate(){
Var button=document. getElementById(‘button’); button. addEventListener(‘click’, send, false);
Window. addEventListener(‘message’, receiver, false);
}
Function send(){
Var name=document. getElementById(‘name’).value; var iframe=document. getElementById(‘iframe’);
Iframe. contentWindow. postMessage(name, ‘http://www.domain2.com’);
}
Function receiver(e){
If(e. origin==’http://www. domain2.com’){
Document. getElementById(‘name’).value=e. data;
}
}
Window. addEventListener(‘load’, initiate, false);
Обратите внимание на функцию send() в коде из листинга 13.18. В методе postMessage() теперь объявляется конкретный целевой домен для отправки сообщения (www.domain2.com). Прочитать это сообщение смогут только документы внутри iframe и принадлежащие указанному источнику.
В функции initiate() в листинге 13.18 мы также добавили прослуши-ватель события message. Задача этого прослушивателя, а также функции receiver() — получить ответ, отправленный документом из iframe. Подробнее об этом поговорим чуть позже.
Давайте пока что изучим код для фрейма и посмотрим, каким образом обрабатывается сообщение из конкретного источника, а также как отправить ответ на это сообщение (для описания структуры фрейма будем использовать старый HTML-документ из листинга 13.15).
Листинг 13.19. Отправка ответа главному документу (iframe. js)
Function initiate(){
Window. addEventListener(‘message’, receiver, false);
}
Function receiver(e){
Var databox=document. getElementById(‘databox’); if(e. origin==’http://www.domain1.com’){
Databox. innerHTML=’допустимое сообщение: ‘+e. data; e. source. postMessage(‘сообщение получено’, e. origin);
}else{
Databox. innerHTML=’недопустимый источник’;
}
}
Window. addEventListener(‘load’, initiate, false);
Фильтрация источника происходит очень просто: мы сравниваем значение свойства origin с доменом, который считаем допустимым источником сообщений. Если выясняется, что это правильный источник, то сообщение выводится на экран, а обратно с использованием значения свойства source отправляется ответ. Мы используем свойство origin, чтобы объявить, что данный ответ будет доступен только тому окну, которое отправило исходное сообщение. Теперь вернитесь к листингу 13.18 и посмотрите, как функция receiver() обрабатывает этот ответ.
Этот пример немного сложнее предыдущих. Мы работаем с двумя разными источниками, поэтому для тестирования примеров кода потребуются два разных домена (или субдомена). Замените названия доменов в коде фактическими именами ваших доменов и загрузите файлы для главного документа в один домен, а файлы для фрейма — в другой.
Главный документ будет загружать во фрейм код из второго домена, и вы сможете наглядно посмотреть, как осуществляется коммуникационный процесс между этими двумя источниками.
Добавить комментарий