Técnicas de Comunicação Cross-Origin: JSONP, Proxy e CORS

Entendendo o Conceito de Cross-Origin

No desenvolvimento web, a segurança do navegador é regida pela Política de Mesma Origem (Same-Origin Policy - SOP). Uma "origem" é definida pela combinação de quatro elementos fundamentais de uma URL:

  • Protocolo: (ex: http, https)
  • Subdomínio: (ex: www, api)
  • Domínio Principal: (ex: site.com)
  • Porta: (ex: 80, 8080, 443)

Considere a URL: http://api.sistema.com.br:9000/v1/usuarios. Se qualquer um dos componentes acima (protocolo, subdomínio, domínio ou porta) for diferente entre a página que faz a requisição e o servidor que recebe, ocorre o que chamamos de Cross-Origin. Por padrão, o JavaScript não tem permissão para ler dados de origens diferentes devido a restrições de segurança, a menos que técnicas específicas sejam implementadas.

Principais Estratégias de Solução

1. Proxy reverso

O método de proxy consiste em utilizar o próprio servidor web da aplicação para atuar como intermediário. Em vez de o navegador tentar acessar dominio-b.com diretamente, ele faz uma requisição para o seu próprio servidor (dominio-a.com/api-proxy), que por sua vez solicita os dados ao destino final e os devolve ao cliente. Como a comunicação entre servidores não sofre restrições de SOP, o problema é resolvido no backend.

2. JSONP (JSON com Padding)

O JSONP explora uma exceção na regra de mesma origem: a tag <script> pode carregar arquivos de qualquer domínio. O cliente define uma função de callback e o servidor retorna os dados encapsulados em uma chamada dessa função.

Limitação importante: O JSONP suporta apenas requisições do tipo GET.

3. CORS / XHR2 (XMLHttpRequest Level 2)

O Cross-Origin Resource Sharing (CORS) é o padrão moderno. Ele utiliza cabeçalhos HTTP para permitir que o servidor informe ao navegador quais origens têm permissão para acessar seus recursos. É suportado por todos os navegadores modernos (IE10+).

Implementação Prática: JSONP

Abaixo, um exemplo de interface para consulta e cadastro de colaboradores utilizando jQuery com suporte a JSONP para a busca.

<!-- Interface do Cliente -->
<div>
    <h2>Painel de Colaboradores</h2>
    <fieldset>
        <legend>Busca de Funcionário</legend>
        <input type="text" id="idBusca" placeholder="Código do funcionário" />
        <button id="btnConsultar">Pesquisar</button>
        <div id="outputBusca"></div>
    </fieldset>

    <fieldset>
        <legend>Cadastro</legend>
        <input type="text" id="nomeColaborador" placeholder="Nome" /><br/>
        <input type="text" id="codColaborador" placeholder="Código" /><br/>
        <select id="generoColaborador">
            <option value="M">Masculino</option>
            <option value="F">Feminino</option>
        </select><br/>
        <button id="btnSalvar">Registrar</button>
        <div id="outputCadastro"></div>
    </fieldset>
</div>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
    // Consulta via JSONP
    $("#btnConsultar").on("click", function() {
        $.ajax({
            type: "GET",
            url: "http://api-remota.test/servico_jsonp.php",
            data: { id: $("#idBusca").val() },
            dataType: "jsonp",
            jsonp: "callback", 
            success: function(res) {
                if(res.status === "ok") {
                    $("#outputBusca").html("<strong>Resultado:</strong> " + res.info);
                } else {
                    $("#outputBusca").html("Erro: " + res.info);
                }
            },
            error: function(err) {
                console.error("Erro na requisição: " + err.status);
            }
        });
    });

    // Cadastro via POST (Exige configuração de CORS no servidor)
    $("#btnSalvar").on("click", function() {
        $.ajax({
            type: "POST",
            url: "http://api-remota.test/servico_jsonp.php",
            dataType: "json",
            data: {
                nome: $("#nomeColaborador").val(),
                codigo: $("#codColaborador").val(),
                sexo: $("#generoColaborador").val()
            },
            success: function(res) {
                $("#outputCadastro").text(res.info);
            }
        });
    });
});
</script>

No backend (PHP), o script deve capturar o parâmetro de callback e retornar o JavaScript executável:

<?php
header("Content-Type: application/json; charset=utf-8");

$repositorio = [
    ["id" => "001", "nome" => "Carlos Silva", "cargo" => "Analista"],
    ["id" => "002", "nome" => "Ana Souza", "cargo" => "Designer"]
];

$metodo = $_SERVER["REQUEST_METHOD"];

if ($metodo === "GET") {
    $cb = $_GET["callback"];
    $idRequisitado = $_GET["id"];
    $encontrado = null;

    foreach ($repositorio as $item) {
        if ($item["id"] == $idRequisitado) {
            $encontrado = $item;
            break;
        }
    }

    if ($encontrado) {
        $resposta = json_encode(["status" => "ok", "info" => "Nome: " . $encontrado["nome"]]);
    } else {
        $resposta = json_encode(["status" => "erro", "info" => "Não localizado"]);
    }

    // Saída específica para JSONP
    echo $cb . "(" . $resposta . ");";

} elseif ($metodo === "POST") {
    // Lógica de salvamento
    echo json_encode(["status" => "ok", "info" => "Cadastro realizado com sucesso"]);
}
?>

Implementação com CORS (XHR2)

Para permitir que o navegador aceite a resposta de um domínio diferente sem usar JSONP, o servidor deve enviar cabeçalhos específicos. Esta é a abordagem recomendada para aplicações modernas, permitindo o uso de GET, POST, PUT e DELETE.

No topo do arquivo PHP (ex: servico_cors.php), adicione:

<?php
// Permite qualquer origem (em produção, substitua * pelo domínio específico)
header("Access-Control-Allow-Origin: *");
// Define os métodos permitidos
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
// Define o tipo de conteúdo
header("Content-Type: application/json; charset=utf-8");

// Resto da lógica do serviço...
?>

Ao utilizar CORS, o jQuery não precisa de dataType: "jsonp". Você pode utilizar dataType: "json" normalmente, e o navegador cuidará da validação dos cabeçalhos de segurança de forma transparente.

Tags: ajax CORS JSONP javascript PHP

Publicado em 7-20 11:07