HTML - Mensagens na Web
Tipos de Mensagens Web
Mensagens de Canal
As Mensagens de Canal permitem que dois ou mais contextos de navegação (janelas, abas ou iframes) se comuniquem, mesmo que estejam em origens diferentes. Elas usam um objeto de canal de mensagem para estabelecer uma conexão entre os contextos e enviar mensagens entre eles.
As Mensagens de Canal são úteis quando você precisa estabelecer uma conexão direta e bidirecional entre contextos. Por exemplo, você pode usá-las para permitir que uma janela pai controle um iframe ou para que duas abas compartilhem dados em tempo real.
Exemplo de Mensagens de Canal
// No primeiro contexto de navegação
const channel = new MessageChannel();
const port1 = channel.port1;
const port2 = channel.port2;
// Envia port2 para o segundo contexto de navegação
window.postMessage('init', '*', [port2]);
// Escuta mensagens na port1
port1.onmessage = (event) => {
console.log('Mensagem recebida:', event.data);
};
// No segundo contexto de navegação
window.onmessage = (event) => {
if (event.data === 'init') {
const port2 = event.ports[0];
port2.onmessage = (event) => {
console.log('Mensagem recebida:', event.data);
};
port2.postMessage('Olá do segundo contexto!');
}
};
Mensagens entre Documentos
As Mensagens entre Documentos, também conhecidas como postMessage, permitem que diferentes contextos de navegação (janelas, abas ou iframes) se comuniquem, mesmo que estejam em origens diferentes. Elas usam o método postMessage()
para enviar um evento de mensagem ao contexto receptor, que pode então tratá-lo usando um ouvinte de eventos.
As Mensagens entre Documentos são úteis quando você precisa de mensagens unidirecionais entre contextos. Por exemplo, quando uma janela pai precisa que um iframe faça algo ou quando uma aba precisa enviar dados para outra aba.
Exemplo de Mensagens entre Documentos
// No contexto de envio
const targetWindow = window.parent; // Ou window.opener, ou document.getElementById('myIframe').contentWindow
targetWindow.postMessage('Olá do remetente!', '*');
// No contexto de recebimento
window.addEventListener('message', (event) => {
if (event.origin === 'http://example.com') {
console.log('Mensagem recebida:', event.data);
}
});
Web Workers
Os Web Workers executam scripts em segundo plano sem afetar o desempenho da página. Eles permitem processamento pesado em uma thread separada para que a página principal permaneça responsiva.
Os Web Workers são úteis para tarefas que levam tempo, como cálculos complexos e processamento de dados.
Exemplo de Web Workers
// No script principal
const worker = new Worker('worker.js');
worker.onmessage = (event) => {
console.log('Mensagem recebida do worker:', event.data);
};
worker.postMessage('Olá do script principal!');
// Em worker.js
self.onmessage = (event) => {
console.log('Mensagem recebida no worker:', event.data);
self.postMessage('Olá do worker!');
};
Considerações de Segurança
Ao usar a Comunicação Web, esteja ciente dos riscos potenciais de segurança e siga as melhores práticas para uma implementação segura.
Um dos principais riscos da Comunicação Web são os ataques de script entre sites (XSS). Se você não validar e limpar os dados recebidos através de mensagens, um atacante pode enviar código malicioso que será executado em sua página. Isso permitiria que ele roubasse dados sensíveis, realizasse ações em nome do usuário ou assumisse o controle da página.
Exemplo de código HTML para risco de XSS
<p>This is a paragraph with extra spaces.</p>
Quando um navegador renderiza este código, ele exibirá o texto como:
This is a paragraph with extra spaces.
Para prevenir ataques XSS, sempre valide e limpe qualquer dado recebido através de mensagens. Não assuma que os dados são seguros apenas porque vêm de outra janela ou worker que você controla. Trate todos os dados recebidos como entrada não confiável e lide com eles de acordo.
Outro risco é ao usar a Comunicação Web para comunicação entre diferentes origens. Tenha cuidado com quais origens você confia. Se você aceitar mensagens de qualquer origem sem verificar, um atacante poderia enviar mensagens de um site malicioso que enganaria sua página, fazendo-a realizar algo que não deveria. Para reduzir esse risco, sempre verifique a propriedade origin
do evento de mensagem e aceite apenas mensagens de origens confiáveis.
Ao usar a Comunicação por Canais, saiba que qualquer contexto que receba uma porta de mensagem tem acesso total a esse canal. Isso significa que eles podem enviar mensagens no canal e até fechá-lo. Portanto, compartilhe portas de mensagem apenas com contextos em que você confia totalmente.
Com Web Workers, um dos principais riscos é que um worker pode travar ou usar muitos recursos se ficar preso em um loop infinito ou tentar fazer muito trabalho. Para evitar isso, use o método Worker.terminate()
para parar um worker imediatamente, se necessário. Estruture seu código de worker para responder às mensagens rapidamente e evite tarefas de longa duração.
Exemplo: Usando o método Worker.terminate()
var myWorker = new Worker('worker.js');
// Encerra o worker após 5 segundos
setTimeout(function() {
myWorker.terminate();
}, 5000);
Este código interrompe o worker após um tempo especificado para evitar o uso excessivo de recursos.
Aqui estão algumas melhores práticas para uma Comunicação Web segura:
- Sempre valide e limpe os dados das mensagens recebidas
- Aceite apenas mensagens de origens confiáveis
- Tenha cuidado ao compartilhar portas de mensagem
- Use
Worker.terminate()
para parar workers com mau comportamento - Mantenha seu código de worker focado e responsivo
- Não use a Comunicação Web para compartilhar dados sensíveis, a menos que seja necessário
- Use criptografia para dados sensíveis, se necessário
- Teste minuciosamente seu código de Comunicação Web para possíveis vulnerabilidades
Exemplos Práticos
Aplicativo de Chat em Tempo Real
Criar um aplicativo de chat em tempo real mostra o poder da Mensagem Web. Aqui está um guia para criar um aplicativo de chat básico usando Mensagem de Canal e Web Workers:
-
Configure a estrutura HTML para a interface do chat, incluindo um campo de entrada para mensagens e um contêiner para exibir o histórico do chat.
-
Crie um novo Web Worker para lidar com o processamento e armazenamento de mensagens. Este worker receberá mensagens do script principal, as armazenará e enviará de volta o histórico de chat atualizado quando solicitado.
Exemplo: Web Worker para Chat (chat_worker.js)
let chatHistory = [];
self.onmessage = (event) => {
if (event.data.type === 'newMessage') {
chatHistory.push(event.data.message);
self.postMessage({ type: 'updateHistory', history: chatHistory });
} else if (event.data.type === 'getHistory') {
self.postMessage({ type: 'updateHistory', history: chatHistory });
}
};
- No script principal, crie um novo canal de Mensagem de Canal e envie uma das portas para o worker.
Exemplo: Script Principal (script.js)
const chatWorker = new Worker('chat_worker.js');
const channel = new MessageChannel();
chatWorker.postMessage({ type: 'init', port: channel.port1 }, [channel.port1]);
- Configure ouvintes de eventos para entrada de mensagens e comunicação do canal. Quando uma nova mensagem é inserida, envie-a para o worker através do canal. Ouça as atualizações do histórico do worker e exiba-as na interface do chat.
Exemplo: Ouvintes de Eventos e Mensagens
const messageInput = document.getElementById('messageInput');
const chatContainer = document.getElementById('chatContainer');
channel.port2.onmessage = (event) => {
if (event.data.type === 'updateHistory') {
const messagesHTML = event.data.history.map(message => `<p>${message}</p>`).join('');
chatContainer.innerHTML = messagesHTML;
}
};
messageInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
const message = messageInput.value;
channel.port2.postMessage({ type: 'newMessage', message });
messageInput.value = '';
}
});
- Quando a página carrega, solicite o histórico inicial do chat ao worker.
Exemplo: Solicitar Histórico Inicial do Chat
chatWorker.postMessage({ type: 'getHistory' });
Com estes passos, você tem um aplicativo de chat em tempo real básico que usa Mensagem Web para comunicar entre o script principal e o Web Worker.
Comunicação Entre Domínios
A Mensagem Web também pode permitir a comunicação entre diferentes domínios usando Mensagem Entre Documentos:
- Na janela pai, crie um iframe com o atributo
src
definido para a URL da página com a qual você deseja se comunicar.
Exemplo: Janela Pai (parent.html)
<iframe id="myIframe" src="https://example.com/iframe.html"></iframe>
- No script do iframe, ouça eventos de mensagem e lide com eles com base no formato de dados esperado.
Exemplo: Script do Iframe (iframe.js)
window.addEventListener('message', function(event) {
if (event.origin === 'https://example.com' && event.data.type === 'userData') {
console.log('Dados do usuário recebidos:', event.data.value);
}
});
- No script da janela pai, obtenha uma referência para a janela do iframe e envie mensagens usando o método
postMessage()
.
Exemplo: Script da Janela Pai (parent.js)
const iframeWindow= document.getElementById('myIframe').contentWindow;
const userData= { name:'João Silva', age :30 };
document.getElementById("myIframe").addEventListener("load", () =>{
iframeWindow.postMessage({type :'userData ', value :userData },'https://example.com ');
});
Com esta configuração, a janela pai pode enviar mensagens contendo dados do usuário para o iframe, e o iframe pode ouvir essas mensagens e processá-las adequadamente. Isso permite uma comunicação segura entre dois contextos, mesmo que estejam hospedados em domínios diferentes.
Ao usar Mensagem Entre Documentos, valide a origem das mensagens recebidas, garantindo que venham de fontes confiáveis, evitando ataques de script entre sites (XSS) e outras vulnerabilidades de segurança.