Resolução de Problemas de Cross-Origin no Front-end

Os problemas de cross-origin no desenvolvimento front-end surgem devido à política de mesma origem dos navegadores, que impede o acesso a recursos de origens diferentes por razões de segurança. Essa limitação impacta diretamente requisições AJAX, bloqueando o acesso a recursos cross-origin por padrão.

Existem diversas técnicas para contornar essa restrição, incluindo JSONP, document.domain com iframes, location.hash com iframes, window.name com iframes, postMessage, CORS (Cross-Origin Resource Sharing), proxies via Node.js, WebSockets e proxies com nginx.

Utilizando JSONP para Comunicação Cross-Origin

JSONP permite a comunicação cross-origin ao explorar a capacidade de carregar scripts de diferentes domínios. A abordagem envolve a criação dinâmica de elementos script que executam uma função de retorno definida pelo cliente.

Exemplo com JavaScript puro:

<script>
var elementoScript = document.createElement('script');
elementoScript.type = 'text/javascript';
elementoScript.src = 'https://api.servidor.com/dados?callback=processarDados';
document.head.appendChild(elementoScript);

function processarDados(info) {
    console.log('Dados recebidos:', info);
}
</script>

Com jQuery:

$.ajax({
    url: 'https://api.servidor.com/dados',
    type: 'GET',
    dataType: 'jsonp',
    jsonpCallback: 'processarDados',
    data: { consulta: 'valor' }
});

Limitação: JSONP suporta apenas requisições GET.

Empregando document.domain com iframes

Esta técnica é aplicável quando domínios compartilham o mesmo domínio principal, mas diferem em subdomínios. Ambas as páginas devem configurar document.domain para o domínio principle comum.

Exemplo no domínio pai (http://www.exemplo.com/pagina-principle.html):

<iframe id="frameFilho" src="http://sub.exemplo.com/pagina-filha.html"></iframe>
<script>
document.domain = 'exemplo.com';
var dadosCompartilhados = 'valorConfidencial';
</script>

Exemplo no domínio filho (http://sub.exemplo.com/pagina-filha.html):

<script>
document.domain = 'exemplo.com';
console.log('Dados do pai:', window.parent.dadosCompartilhados);
</script>

Comunicação Cross-Origin via location.hash e iframes

Este método utiliza iframes encadeados para transmitir dados através do fragmento da URL (hash). Uma página intermediária no mesmo domínio que a origem facilita a comunicação.

Implementação envolve três páginas: uma no domínio A (origem), uma no domínio B (destino intermediário) e outra no domínio A (intermediário para retorno).

Exemplo simplificado no domínio A:

<iframe id="frameIntermediario" src="https://outro-dominio.com/pagina-intermediaria.html" style="display:none;"></iframe>
<script>
var frame = document.getElementById('frameIntermediario');
// Envia dados via hash após carregamento
frame.onload = function() {
    frame.src += '#dados=teste';
};

// Função para receber dados de retorno
function receberDados(info) {
    alert('Dados recebidos: ' + info);
}
</script>

Utilizando window.name para Transferência de Dados

A propriedade window.name mantém seu valor mesmo após navegações entre domínios, permitindo a trensferência de dados de até 2MB. Um iframe é usado para carregar a página cross-origin e, em seguida, redirecionado para uma página no mesmo domínio para ler os dados.

Exemplo:

function obterDadosCrossOrigin(urlDestino, callback) {
    var etapa = 0;
    var frame = document.createElement('iframe');
    frame.src = urlDestino;

    frame.onload = function() {
        if (etapa === 1) {
            callback(frame.contentWindow.name);
            frame.parentNode.removeChild(frame);
        } else if (etapa === 0) {
            frame.contentWindow.location = 'https://meu-dominio.com/pagina-proxy.html';
            etapa = 1;
        }
    };
    document.body.appendChild(frame);
}

// Uso
obterDadosCrossOrigin('https://outro-dominio.com/dados.html', function(dados) {
    console.log('Dados obtidos:', dados);
});

Comunicação Cross-Origin com postMessage

A API postMessage do HTML5 permite a troca segura de mensagens entre janelas, iframes ou pop-ups de diferentes origens.

Exemplo de envio e recebimento de mensagens:

// No frame que envia a mensagem
var frameDestino = document.getElementById('frameExterno');
var mensagem = { acao: 'solicitar', conteudo: 'valor' };
frameDestino.contentWindow.postMessage(JSON.stringify(mensagem), 'https://outro-dominio.com');

// No frame que recebe a mensagem
window.addEventListener('message', function(evento) {
    if (evento.origin === 'https://meu-dominio.com') {
        var dadosRecebidos = JSON.parse(evento.data);
        console.log('Mensagem recebida:', dadosRecebidos);
        // Responder pode ser feito com evento.source.postMessage(...)
    }
}, false);

Implementando CORS (Cross-Origin Resource Sharing)

CORS é um mecanismo padrão que permite que servidores especifiquem quais origens podem acessar seus recursos. Requer configuração no servidor, e no cliente para requisições com credenciais.

Exemplo com XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true; // Inclui cookies na requisição
xhr.open('GET', 'https://api.externa.com/recursos', true);
xhr.onload = function() {
    if (xhr.status === 200) {
        console.log('Resposta:', xhr.responseText);
    }
};
xhr.send();

Configuração no servidor (exemplo em Node.js com Express):

app.use(function(requisicao, resposta, proximo) {
    resposta.header('Access-Control-Allow-Origin', 'https://meu-dominio.com');
    resposta.header('Access-Control-Allow-Credentials', 'true');
    resposta.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    proximo();
});

Proxy Cross-Origin com Node.js

Um servidor proxy em Node.js atua como intermediário, encaminhando requisições do cliente para o servidor de destino, evitando restrições cross-origin no navegador.

Exemplo usando Express e http-proxy-middleware:

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();

app.use('/api', createProxyMiddleware({
    target: 'https://servidor-alvo.com',
    changeOrigin: true,
    onProxyRes: function(proxyRes, req, res) {
        res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
    }
}));

app.listen(3000);

Utilizando WebSockets para Comunicação Cross-Origin

WebSockets permitem comunicação bidirecional em tempo real entre cliente e servidor, e são isentos da política de mesma origem.

Exemplo com Socket.IO:

<script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
<script>
var socket = io('https://servidor-websocket.com');
socket.on('connect', function() {
    socket.emit('evento', { dado: 'valor' });
    socket.on('resposta', function(msg) {
        console.log('Mensagem do servidor:', msg);
    });
});
</script>

Proxy Cross-Origin com Nginx

Nginx pode ser configurado como proxy reverso para encaminhar requisições cross-origin, lidando com CORS e reescrita de cookies.

Exemplo de configuração no nginx:

server {
    listen 80;
    server_name meu-dominio.com;

    location /api/ {
        proxy_pass https://servidor-externo.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
    }
}

Isso permite que o frontend faça requisições para /api/ no mesmo domínio, enquanto o nginx redireciona para o servidor externo, resolvendo os problemas de cross-origin.

Tags: JSONP CORS iframe postMessage WebSocket

Publicado em 7-7 02:20