Cross-origin é uma restrição de segurança implementada pelos navegadores para evitar que scripts acessem recursos de origens diferentes. Entre as principais abordagens para resolver isso estão JSONP e CORS. Outras soluções, como proxies, são abordadas em discussões separadas.
JSONP
JSONP (JSON with Padding) é uma técnica que aproveita a flexibilidade das tags <script> para contornar a mesma política de origem. A ideia é encapsular os dados JSON em uma chamada de função callback.
O prcoesso funciona da seguinte forma:
- O cliente insere dinamicamente uma tag <script> no documento, definindo o atributo
srccomo o endpoint da API. Isso limita o método a GET. - O srevidor recebe a requisição, extrai o parâmetro de callback (ex.:
callbackFunc) dos query parameters. - O servidor prepara a resposta no formato
callbackFunc({"dados": "exemplo"})e a retorna com o cabeçalhoContent-Type: application/javascript; charset=utf-8. - O navegaodr executa o script retornado, invocando a função callback com os dados.
Exemplo de código no cliente:
function processarDados(resultado) {
console.log('Dados recebidos:', resultado);
}
const scriptTag = document.createElement('script');
scriptTag.src = 'http://api.servidor.com/dados?callback=processarDados';
document.body.appendChild(scriptTag);
Desvantagens do JSONP:
- Suporta apenas requisições GET.
- Dificuldade no debugging, pois erros não retornam códigos de status HTTP adequados.
- Riscos de segurança, como injeção de código se o serviço JSONP for comprometido.
Vantagens:
- Compatível com navegadores antigos que não suportam CORS.
- Permite acesso a recursos em servidores sem configuração de CORS.
CORS
CORS (Cross-Origin Resource Sharing) é um mecanismo que utiliza cabeçalhos HTTP para permitir ou restringir acesso cross-origin. Ele se divide em requisições simples e não-simples.
Requisições Simples
Uma requisição é considerada simples se:
- O método HTTP é HEAD, GET ou POST.
- Os cabeçalhos personalizados estão restritos a Accept, Accept-Language, Content-Language, Last-Event-ID ou Content-Type com valores específicos (application/x-www-form-urlencoded, multipart/form-data, text/plain).
Para requisições simples, o navegador inclui automaticamente o cabeçalho Origin na requisição. O servidor responde com cabeçalhos como:
Access-Control-Allow-Origin: Especifica a origem permitida (ex.:http://cliente.com) ou*para qualquer origem.Access-Control-Allow-Credentials: Setrue, permite o envio de cookies.Access-Control-Expose-Headers: Lista de cabeçalhos adicionais acessíveis pelo cliente.
Exemplo de cabeçalhos na resposta do servidor:
Access-Control-Allow-Origin: http://cliente.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Info
Para enviar cookies, o cliente deve configurar a propriedade withCredentials em requisições AJAX:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.servidor.com/dados', true);
xhr.withCredentials = true;
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
Requisições Não-Simples
Requisições que não atendem aos critérios simples, como métodos PUT ou DELETE, ou cabeçalhos personalizados, geram uma requisição de pré-verificação (preflight). O navegador envia uma requisição OPTIONS para o servidor, incluindo:
Origin: A origem do cliente.Access-Control-Request-Method: O método HTTP a ser usado.Access-Control-Request-Headers: Cabeçalhos personalizados que serão enviados.
Exemplo de requisição preflight:
OPTIONS /recurso HTTP/1.1
Origin: http://cliente.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Token
O servidor responde com os cabeçalhos CORS apropriados:
Access-Control-Allow-Origin: http://cliente.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Token, Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
Após a pré-verificação bem-sucedida, o navegador prossegue com a requisição original. Os cabeçalhos Access-Control-Allow-Methods e Access-Control-Allow-Headers são relevantes apenas na resposta ao OPTIONS, enquanto Access-Control-Allow-Origin deve estar presente tanto na preflight quanto na requisição real para autorização.