JSONP: A arma secreta do frontend do passado
\nImagine que você é um desenvolvedor web em 2010. Você precisa obter dados de um servidor de terceiros, por exemplo, a previsão do tempo ou a cotação de moedas. Você escreve uma simples requisição fetch, mas no console do navegador aparece um erro vermelho: «No 'Access-Control-Allow-Origin' header is present». Familiar?
Isso é a Same-Origin Policy (política de mesma origem) impedindo seu JavaScript de sair do domínio de origem. Mas como funcionavam os widgets de previsão do tempo, botões «Compartilhar» e contadores de visitas? A resposta é simples: eles usavam JSONP — um truque engenhoso sobre o qual vamos falar hoje.
\nNeste artigo, responderemos à pergunta popular do Stack Overflow: «What is JSONP, and why was it created?» — em linguagem simples, com exemplos de código e sem teoria desnecessária.
\n\n1. O problema: Por que o navegador bloqueia requisições?
\nO navegador é paranóico. Ele protege o usuário contra ataques XSS e roubo de dados. A Same-Origin Policy permite que o JavaScript leia respostas apenas do mesmo domínio, protocolo e porta.
\nExemplo de bloqueio:
\n// Este código causará um erro CORS\nfetch('https://api.distant-server.com/data')\n .then(response => response.json())\n .then(data => console.log(data));\nMas há uma exceção: as tags <script>. O navegador carrega scripts de qualquer domínio sem problemas! É exatamente essa brecha que o JSONP utiliza.
\n\n2. A solução: JSONP — JSON com Padding
\nJSONP (JSON with Padding) não é uma tecnologia nem um formato de dados, mas sim um padrão (gambiarra) que contorna a Same-Origin Policy através da tag <script>.
A ideia é simples: em vez de fazer uma requisição via XMLHttpRequest, criamos dinamicamente um elemento <script>, apontamos para a URL do servidor, e o servidor retorna não um JSON, mas um código JavaScript que chama nossa função com os dados.
Como é um JSON comum:
\n// Resposta do servidor (JSON comum)\n{"name": "PythonLib", "topic": "JSONP"}\n\nComo é um JSONP:
\n// Resposta do servidor (JSONP)\nmyCallback({"name": "PythonLib", "topic": "JSONP"});\nA diferença é colossal: no segundo caso, o servidor envolve os dados em uma chamada de função myCallback. Esse é o tal padding (invólucro).
3. Prática: Escrevendo uma requisição JSONP manualmente
\nVamos implementar um cliente JSONP em JavaScript puro. Isso ajudará a entender a mágica.
\n\nfunction jsonp(url, callbackName) {\n // 1. Cria uma função global (callback)\n window[callbackName] = function(data) {\n console.log('Dados recebidos:', data);\n delete window[callbackName]; // Limpa a bagunça\n document.body.removeChild(script);\n };\n\n // 2. Cria a tag script\n const script = document.createElement('script');\n script.src = `${url}?callback=${callbackName}`; // Passa o nome do callback\n script.onerror = function() {\n console.error('Erro ao carregar JSONP');\n delete window[callbackName];\n document.body.removeChild(script);\n };\n\n // 3. Adiciona ao DOM — o navegador carrega e executa o script imediatamente\n document.body.appendChild(script);\n}\n\n// Usando:\njsonp('https://api.example.com/data', 'handleData');\nComo funciona passo a passo:
\n- \n
- Criamos uma função global
handleData. \n - Adicionamos a tag
<script>com a URL do servidor. Na URL, passamos o parâmetro?callback=handleData. \n - O servidor que suporta JSONP vê o parâmetro
callbacke retorna não um JSON, mas um JavaScript:handleData({...}). \n - O navegador executa esse script, nossa função é chamada e recebemos os dados. \n
4. Por que JSONP é o mal? (Desvantagens)
\nSe você pensou: «Legal, vou usar em tudo