Capítulo 13 API Communication – 2

Capítulo 13 API Communication - 2

13.1   Cross Document Messaging

Esta parte de lo que llamamos API Communication es conocida oficialmente como API Web Messaging. Cross Document Messaging es una técnica que permite a aplicaciones de diferentes orígenes comunicarse entre sí. Aplicaciones funcionando en diferentes cuadros, ventanas o pestañas (o incluso otras APIs) pueden comunicarse ahora aprovechando esta tecnología. El procedimiento es simple: publicamos un mensaje desde un documento y lo procesamos en el documento destino.

Constructor

Para publicar mensajes, la API provee el método postMessage ():

postMessage(mensaje, destino) Este método es aplicado al contentWindow del objeto Window que recibe el mensaje. El atributo mensaje es una cadena de texto representando el mensaje a transmitir, y el atributo destino es el dominio del documento destino (que puede ser una URL o un puerto, como veremos más adelante). El destino puede ser declarado como un dominio específico, como cualquier documento usando el símbolo *, o como el mismo origen del documento que envía el mensaje usando el símbolo /. El método puede también incluir un array de puertos como tercer atributo.

Evento message y propiedades

El método de comunicación es asíncrono. Para escuchar por mensajes enviados por un documento en particular, la API ofrece el evento message, el cual incluye algunas propiedades con información sobre la operación:

data Esta propiedad retorna el contenido del mensaje.

origin Esta propiedad retorna el origen del documento que envió el mensaje, generalmente el dominio. Este valor puede ser usado luego para enviar un mensaje de regreso. source Esta propiedad retorna un objeto usado para identificar a la fuente del mensaje. Este valor puede ser usado para apuntar al documento que envía el mensaje, como veremos más adelante.

Enviando mensajes

Para crear un ejemplo de esta API, tenemos que considerar lo siguiente: la comunicación ocurre entre diferentes ventanas (ventanas, cuadros, pestañas u otras APIs), debido a esto debemos generar documentos y códigos para cada extremo del proceso. Nuestro ejemplo incluye una plantilla con un iframe (cuadro interno) y los códigos Javascript apropiados para cada documento HTML. Comencemos por el documento principal:

<!DOCTYPE html>

<html lang=»es»>

<head>

<title>Cross Document Messaging</title>

<link rel=»stylesheet» href=»messaging.css»>

<script src=»messaging.js»></script>

</head>

<body>

<section id=»cajaformulario»>

<form name=»formulario»>

<p>Su nombre: <input type=»text» name=»nombre» id=»nombre»

required></p>

<p><input type=»button» name=»boton» id=»boton»

value=»Enviar»></p>

</form>

</section>

<section id=»cajadatos»>

<iframe id=»iframe» src=»iframe.html» width=»500″

height=»350″></iframe>

</section>

</body>

</html>

Listado 13-12. Plantilla para comunicación entre documentos.

Como podemos ver, al igual que en plantillas previas, incluimos dos elementos <section>, pero esta vez cajadatos contiene un <iframe> que cargará el archivo iframe.html. Vamos a volver a esto en un momento. Antes agreguemos algunos estilos a esta estructura:

#caj aformulario{

float: left;

padding: 20px;

border: 1px solid #999999;

}

#caj adatos{

float: left;

width: 500px;

margin-left: 20px;

padding: 20px;

border: 1px solid #999999;

}

Listado 13-13. Estilos para las cajas en pantalla (messaging.css).

El código Javascript para el documento principal tiene que tomar el valor del campo nombre del formulario y enviarlo como un mensaje al documento dentro del iframe usando el método postMessage () :

function iniciar(){

var boton=document.getElementById(‘boton’);

boton.addEventListener(‘click’, enviar, false);

}

function enviar(){

var nombre=document.getElementById(‘nombre’).value;

var iframe=document.getElementById(‘iframe’);

iframe.contentWindow.postMessage(nombre, ‘*’);

}

window.addEventListener(‘load’, iniciar, false);

Listado 13-14. Publicando un mensaje (messaging. js).

En el código del Listado 13-14, el mensaje fue compuesto por el valor del campo nombre. El símbolo * fue usado como valor de destino para enviar este mensaje a cualquier documento dentro del iframe (sin importar su origen).

Una vez que el botón «Enviar» es presionado, la función enviar() es llamada y el valor del campo es enviado al contenido del iframe. Ahora es momento de tomar ese mensaje y procesarlo. Recuerde que el documento destinado a ser abierto en un iframe es exactamente igual a uno abierto en la ventana principal. El iframe simplemente simula una ventana dentro del documento. Por este motivo, vamos a crear una pequeña plantilla similar a la anterior pero solo con el propósito de mostrar la información recibida:

<!DOCTYPE html>

<html lang=»es»>

<head>

<title>iframe window</title>

<script src=»iframe.js»></script>

</head>

<body>

<section>

<div><b>Mensaje desde la ventana principal:</b></div>

<div id=»cajadatos»></div>

</section>

</body>

</html>

Listado 13-15. Plantilla para el iframe (iframe.html).

Esta plantilla tiene su propia cajadatos que será usada para mostrar el mensaje recibido en la pantalla, y también su propio código Javascript para procesarlo:

function iniciar(){

window.addEventListener(‘message’, receptor, false);

}

function receptor(e){

var caj adatos=document.getElementById(‘caj adatos’); cajadatos.innerHTML=’mensaje desde: ‘+e.origin+'<br>’;

caj adatos.innerHTML+=’mensaj e:   ‘+e.data;

}

window.addEventListener(‘load’, iniciar, false);

Listado 13-16. Procesando los mensajes desde el destino (iframe.js).

Acorde a lo que explicamos anteriormente, para escuchar los mensajes la API provee el evento message y algunas propiedades. En el código del Listado 13-16, una escucha para este evento fue agregada y la función receptor() fue declarada para responder al mismo. Esta función muestra el contenido del mensaje usando la propiedad data e información acerca del documento que lo envió usando el valor de origin.

Recuerde que este código pertenece al documento HTML del iframe, no al documento principal del Listado 13-12. Estos son dos documentos diferentes con sus propios entornos, objetivos y códigos (uno es abierto en la ventana principal y el otro dentro del iframe).

Hágalo usted mismo: Hay un total de cinco archivos que tienen que ser creados y subidos al servidor para poder probar este ejemplo. Primero, cree un nuevo archivo HTML con el código del Listado 13-12 que será nuestro documento principal. Este documento también requiere el archivo messaging.css con los estilos del Listado 13-13 y el archivo messaging.js con el código Javascript del Listado 13-14. La plantilla del Listado 13-12 contiene un elemento <iframe> con el archivo iframe.html como su fuente. Necesitará crear también este archivo y copiar en su interior el código del Listado 13-15 y además generar el correspondiente archivo iframe.js con los códigos del Listado 13-16. Suba todos los archivos a su servidor, abra el primer documento HTML en su navegador y envíe su nombre o cualquier texto al iframe usando el formulario en pantalla.

Filtros y múltiples orígenes

Lo que hemos hecho hasta ahora no es una práctica recomendable, especialmente si consideramos asuntos de seguridad. El código en el documento principal envía un mensaje a un iframe específico, pero no controla los documentos dentro de ese iframe que estarán autorizados a leerlo (cualquier documento dentro del iframe podrá leer el mensaje). Del mismo modo, el código de nuestro ejemplo para el iframe no controla el origen y procesa todo mensaje recibido. Ambas partes del proceso de comunicación tienen que ser mejoradas para prevenir abusos o errores.

En el siguiente ejemplo, vamos a corregir esta situación y estudiar el procedimiento a seguir para responder a un mensaje del documento origen usando otra propiedad del evento message llamada source.

<!DOCTYPE html>

<html lang=»es»>

<head>

<title>Cross Document Messaging</title>

<link rel=»stylesheet» href=»messaging.css»>

<script src=»messaging.js»></script>

</head>

<body>

<section id=»cajaformulario»>

<form name=»formulario»>

<p>Su nombre: <input type=»text» name=»nombre» id=»nombre»

required></p>

<p><input type=»button» name=»boton» id=»boton»

value=»Enviar»></p>

</form>

</section>

<section id=»cajadatos»>

<iframe id=»iframe» src=»http://www.dominio2.com/iframe.html»

width=»500″ height=»350″></iframe>

</section>

</body>

</html>

Listado 13-17. Comunicándonos con un origen/destino específicos.

Supongamos que el nuevo documento HTML con el código del Listado 13-17 está localizado en www.dominio1.com, pero el código para el iframe es cargado desde una segunda ubicación en www.dominio2.com. Para prevenir abusos y errores, necesitaremos declarar estos dominios en el código y ser específicos sobre quién estará autorizado a leer los mensajes y desde dónde.

En el código del Listado 13-17, no estamos solo cargando el archivo HTML para el iframe sino declarando la ruta completa hacia otro servidor (www.dominio2.com). El documento principal se encontrará en www.dominio1.com y el contenido del iframe en www.dominio2.com. Los siguientes códigos consideran esta situación:

function iniciar(){

var boton=document.getElementByld(‘boton’);

boton.addEventListener(‘click’, enviar, false);

window.addEventListener(‘message’, receptor, false);

}

function enviar(){

var nombre=document.getElementById(‘nombre’).value;

var iframe=document.getElementById(‘iframe’);

iframe.contentWindow.postMessage(nombre, ‘http://www.dominio2.com’);

}

function receptor(e){

if(e.origin==’http://www.dominio2.com’){

document.getElementById(‘nombre’).value=e.data;

}

}

window.addEventListener(‘load’, iniciar, false);

Listado 13-18. Comunicándonos con orígenes específicos (messaging.js).

Preste atención a la función enviar() en el Listado 13-18. El método postMessage() ahora declara un destino específico para el mensaje (www.dominio2.com). Solo documentos dentro del iframe y que provengan de ese origen específico podrán leer este mensaje.

En la función iniciar() del Listado 13-18 también agregamos una escucha para el evento message. El propósito de esta escucha y de la función receptor() es recibir la respuesta enviada desde el iframe. Esto cobrará sentido en unos minutos.

Veamos ahora el código Javascript ejecutado en el iframe que nos ayudará a entender cómo un mensaje proveniente de un origen específico es procesado y cómo respondemos al mismo (usaremos exactamente el mismo documento HTML del Listado 13-15 para el iframe).

function iniciar(){

window.addEventListener(‘message’, receptor, false);

}

function receptor(e){

var caj adatos=document.getElementByld(‘caj adatos ‘ ) ; if(e.origin==’http://www.dominio1.com’){

cajadatos.innerHTML=’mensaje válido: ‘+e.data;

e.source.postMessage(‘mensaje recibido’, e.origin);

}else{

caj adatos.innerHTML=’origen inválido’;

}

}

window.addEventListener(‘load’, iniciar, false);

Listado 13-19. Respondiendo al documento principal (i frame .js).

Filtrar el origen es tan simple como comparar el valor de la propiedad origin con el dominio del cual queremos leer los mensajes. Una vez que comprobamos que el origen es válido, el mensaje es mostrado en pantalla y luego una respuesta es enviada de regreso aprovechando el valor de la propiedad source. La propiedad origin es también usada para declarar que esta respuesta estará solo disponible para la ventana que envió el mensaje en primer lugar. Ahora puede regresar al Listado 13-18 para comprender cómo la función receptor () procesará esta respuesta.

Hágalo usted mismo: Este último ejemplo es un poco engañoso. Estamos usando dos orígenes diferentes, por lo que necesitará dos dominios diferentes (o subdominios) para comprobar el funcionamiento de los códigos. Reemplace los dominios declarados en los códigos por los suyos propios y luego suba los archivos correspondientes al documento principal en uno y los correspondientes al iframe en el otro. El documento principal cargará en el iframe el código desde el segundo dominio y así podrá ver cómo funciona el proceso de comunicación entre estos dos orígenes diferentes.

Publicaciones Similares