Web Messaging API

Web Messaging API

Provavelmente em algum projeto você já foi obrigado a utilizar um iframe para carregar conteúdo de uma página externa, e desde então só era possível visualizar o conteúdo do mesmo, e ele funciona como uma sandbox onde não existe comunicação com sua aplicação. Nas especificações do W3C o HTML5 possui algumas APIs para comunicação. Este post trata especificamente uma delas: a HTML5 Web Messaging API que resolve o problema descrito.

API

Essa é uma API simples, que resolve o problema de comunicação entre aplicações hospedadas em diferentes origens. Antes da existência dessa API, não era possível essa comunicação devido a “política da mesma origem”, onde não é possivel uma programação client-side de uma origem acesse ou interfira em um documento de outra origem. Resumindo: um script hopedado em um lugar não consegue acessar o DOM de um documento de outra origem. A origem pode ser 3 tipos: protocolo, host e porta.

Exemplo: digamos que a origem de minha aplicação seja o URL: http://openblog.com.br/mensagem.php

URL Mesma origem? Razão
http://openblog.com.br/recebe.php Sim -
http://openblog.com.br Sim -
https://openblog.com.br/auth.php Não Protocolo diferente
http://openblog.com.br:9000/recebe.php Não Porta Diferente
http://blog.openblog.com.br/recebe.php Não Host Diferente

Método window.postMessage()

Este método é o responsável por criar uma mensagem a ser enviada para um objeto window em uma origem diferente. O padrão do tipo da mensagem é uma string. O método recebe três parâmetros: dois obrigatórios e um opcional.

  window.postMessage(mensagem, destino, [portas])  
  //mensagem: string a ser enviada
  //destino: endereço a ser enviado
  //portas: array de portas válidas para o destino

O destino pode ser um URL absoluto, um caractere curinga * que servirá para qualquer destino ou um caractere barra / que adota a política da mesma origem (ou seja, apenas o mesmo host da página).

Evento message

A API prevê o evento message que é disparado no documento destino da mensagem. Quando disparado ele chama a seguinte função callback:

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

  function receberMsg(e){
      //faça algo com a mensagem
  }

A função receberMsg como o nome já diz, recebe um parâmetro que retorna um objeto-evento com as propriedades:

  e.data //text da mensagem
  e.origin //origem da mensagem
  e.lastEventId //string identificadora do último evento
  e.source //retorna WindowProxy do destino
  e.ports //array das portas enviadas

Mãos na massa

Vamos criar a situação mencionada no início do post, onde um documento de origem A tenta se comunicar com um documento de origem B. A idéia é postar uma mensagem e ela aparecer no iframe. Vamos lá…

  • Documento A (http://openblog.github.com/demos/html5_msg_origin)
  //Javascript
  window.onload = function(){
    var objIframe = document.getElementsByTagName('iframe')[0];
    var btnEnviar =  document.getElementsByTagName('button')[0];

    btnEnviar.onclick = function(){
      var textoMsg = document.getElementsByTagName('input')[0].value;

      if(textoMsg == ''){
        alert('Digite uma mensagem!');
      } else{
        objIframe.contentWindow.postMessage(textoMsg, 'http://labs.vagnersantana.com');
      }
    }
  }
  <!-- HTML -->
  <section>
    <p>
      <label>Mensagem: <input type="text"></label>
      <button type="button">Enviar mensagem</button>
    </p>
    <iframe src="http://labs.vagnersantana.com/html5_msg_iframe.html"></iframe>
  </section>
  • Documento B (http://labs.vagnersantana.com/html5_msg_iframe.html)
  //Javascript 
  if(window.addEventListener){
    window.addEventListener('message', receberMsg, false);
  } else{
    window.attachEvent("onmessage", receberMsg);
  };

  function receberMsg(e){
    var msg;
    var containerMsg = document.getElementById('recebe-msg');

    if(e.origin == 'http://openblog.github.com'){
      msg = 'Mensagem recebida: <br>';
      msg += 'Msg: ' + e.data + '<br>';
      msg += 'Origem: ' + e.origin;

      containerMsg.innerHTML = msg;
    } else{
      containerMsg.innerHTML = 'Origem não autorizada!';
    }
  }
  //HTML
  <p id="recebe-msg"></p>

O Web Messaging envia uma string, porém não precisa se desesperar e pensar em ir separando os dados por | ou ; pois felizmente existe o maravilhoso JSON que oferece a funcionalidade de se transformar em string com o método JSON.stringify e recuperá-lo usando o JSON.parse(), desta forma podemos trocar e manipular dados de maneira fácil somando o Web Messaging com JSON.

Can i use ?

Can i use table of Web Messaging API

Para ver a API em ação é só clicar no demo abaixo, sinta-se à vontade em inspecionar o código e também fazer um fork no github. Divirta-se.

Referências