Problemas de Cross-Domain e Suas Soluções

Para resolver esse problema, o mecanismo CORS (Compartilhamento de Recursos de Origem Cruzada) foi desenvolvido. Este artigo explorará em detalhes as causas dos problemas de cross-domain, o funcionamento do mecanismo CORS e as soluções comuns para lidar com esses desafios em desenvolvimento real.

  1. O que é Cross-Domain?

Cross-domain refere-se à situação em que, no navegador, o script de uma página web tenta acessar recursos de outro domínio (com protocolo, domínio e porta diferentes), e o navegador bloqueia essa requisição. Para garantir a segurança do usuário, os navegadores utilizam a política de mesma origem, que permite apenas requisições de mesma origem.

  • Mesma origem: refere-se a protocolo, domínio e porta idênticos.
  • Cross-domain: se protocolo, domínio ou porta forem diferentes, é considerada uma requisição cross-domain.

Por exemplo, se a página frontend estiver em http://localhost:3000 e o serviço API em http://api.exemplo.com, a requisição do frontend para a API do backend será uma requisição cross-domain.

  1. Por que precisamos de CORS?

Para compensar as limitações da política de mesma origem, o mecanismo CORS (Cross-Origin Resource Sharing) foi desenvolvido. É um protocolo entre navegador e servidor usado para permitir requisições cros-domain. Quando um navegador faz uma requisição cross-domain, o servidor adiciona cabeçalhos específicos de CORS na resposta, indicando quais requisições são permitidas, permitindo assim o compartilhamento de recursos entre origens diferentes.

  1. Detalhes do mecanismo CORS

O funcionamento do CORS baseia-se em cabeçalhos específicos em requisições e respostas HTTP. O navegador adiciona automaticamente alguns cabeçalhos ao fazer requisições cross-domain, enquanto o servidor precisa retornar cabeçalhos de permissão cross-domain com base nesses cabeçalhos. CORS tem principalmente dois tipos de requisições: requisições simples e requisições não simples, sendo que as requisições não simples exigem uma requisição de verificação prévia (Preflight) para confirmar se a operação cross-domain é permitida.

3.1 Requisições simples e requisições de verificação prévia

  • Requisição simples: são consideradas requisições que atendem a condições específicas, como usar métodos GET ou POST, e cabeçalhos de requisição limitados a Accept, Content-Type, etc.
  • Requisição não simples: se a requisição não atender às condições de requisição simples (como usar métodos PUT, DELETE, ou incluir cabeçalhos personalizados), o navegador primeiro anviará uma requisição de verificação prévia. Esta é uma requisição OPTIONS que pergunta ao servidor se a requisição cross-domain real é permitida.
  1. Soluções comuns para problemas de cross-domain

Existem várias maneiras de resolver problemas de cross-domain. Abaixo estão algumas soluções comuns.

4.1 Usando cabeçalhos CORS (solução mais comum)

A configuração de cabeçalhos CORS no lado do servidor é a solução mais comum para cross-domain. Ao adicionar cabeçalhos CORS específicos nos cabeçalhos de resposta HTTP do servidor, o servidor pode informar explicitamente ao navegador quais requisições cross-domain são permitidas.

Exemplo: Node.js (Express)

No Node.js, geralmente usamos o middleware cors para configurar cross-domain. Aqui está um exemplo de configuração simples:


const servidor = require('express');
const configuracaoCross = require('cors');

const aplicacao = servidor();

// Configuração CORS
const opcoesCors = {
  origemPermitida: 'http://exemplo.com', // Origem permitida
  metodosPermitidos: ['GET', 'POST'],    // Métodos HTTP permitidos
  cabecalhosPermitidos: ['Content-Type', 'Authorization'], // Cabeçalhos de requisição permitidos
  credenciais: true                      // Permitir credenciais
};

aplicacao.use(configuracaoCross(opcoesCors));

aplicacao.get('/dados', (requisicao, resposta) => {
  resposta.json({ mensagem: 'Requisição cross-domain bem-sucedida' });
});

aplicacao.listen(3000, () => {
  console.log('Servidor iniciado');
});

Neste exemplo:

  • origemPermitida especifica o domínio de origem permitido para requisições cross-domain.
  • metodosPermitidos define os métodos HTTP permitidos.
  • cabecalhosPermitidos lista os cabeçalhos de requisição permitidos.
  • credenciais definido como true permite que requisições cross-domain carreguem Cookies ou informações de autenticação.

Exemplo: Java (Spring Boot)

No Spring Boot, podemos usar a anotação @CrossOrigin para suporte a cross-domain:


import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ControladorDados {

    @CrossOrigin(origins = "http://exemplo.com", allowedHeaders = "*", allowCredentials = "true")
    @GetMapping("/dados")
    public String obterDados() {
        return "Requisição cross-domain bem-sucedida";
    }
}

A anotação @CrossOrigin permite configurar configurações de cross-domain para interfaces ou classes específicas. Podemos especificar os domínios permitidos (origins), cabeçalhos de requisição permitidos (allowedHeaders), e se requisições cross-domain podem carregar credenciais (allowCredentials).

4.2 Servidor Proxy

Outra solução comum para problemas de cross-domain é usar um servidor proxy. A requisição do frontend primeiro é enviada para um servidor proxy de mesma origem do frontend, que então encaminha a requisição para o servidor de destino, contornando assim as limitações de cross-domain do navegador. Ferramentas de construção frontend como Webpack oferecem funcionalidades de proxy durante o desenvolvimento.

Exemplo: Proxy Node.js


const http = require('http');
const proxy = require('http-proxy');

// Criar servidor proxy
const servidorProxy = proxy.createProxyServer({});

// Criar servidor simples para encaminhar requisições
http.createServer((requisicao, resposta) => {
  servidorProxy.web(requisicao, resposta, { destino: 'http://exemplo.com' });
}).listen(8000);

Neste exemplo, todas as requisições são enviadas primeiro para http://localhost:8000, e então o servidor proxy encaminha a requisição para http://exemplo.com, permitindo assim requisições cross-domain.

4.3 JSONP (apenas para requisições GET)

JSONP (JSON com Preenchimento) é uma técnica que implementa cross-domain inserindo dinamicamente tags <script>. Como as tags <script> não têm limitações de cross-domain, podemos usar essa característica para contornar a política de mesma origem. Embora o JSONP tenha sido muito popular no passado, devido à sua limitação de suportar apenas requisições GET e a certos riscos de segurança, não é mais recomendado em desenvolvimento web moderno.

4.4 Usando WebSocket

WebSocket é um protocolo de comunicação bidirecional que não é limitado pela política de mesma origem, podendo ser usado para comunicação cross-domain. WebSocket é especialmante adequado para cenários que exigem comunicação em tempo real, como chats instantâneos, jogos online e outras aplicações.

Exemplo: Cliente WebSocket


const socket = new WebSocket('ws://exemplo.com/socket');

// Escutar conexão estabelecida
socket.onopen = function(evento) {
  console.log('WebSocket conectado');
  socket.send('Olá Servidor');
};

// Escutar recebimento de mensagens
socket.onmessage = function(evento) {
  console.log('Mensagem recebida:', evento.data);
};

Com WebSocket, o cliente pode estabelecer uma conexão persistente com o servidor, evitando problemas de cross-domain.

Tags: CORS cross-domain same-origin-policy web-development nodejs

Publicado em 6-2 18:13 por Thomas