JSONP ou "JSON with padding" é um complemento ao formato de dados JSON. Ele provê um método para enviar requisições de dados de um servidor para um domínio diferente, uma coisa proibida pelos navegadores típicos por causa da Política de mesma origem.
Com a Política de mesma origem, uma página servida de server1.example.com não pode normalmente se conectar ou se comunicar com servidores diferentes de server1.example.com. Uma exceção é a tag HTML <script>
. Explorando a política aberta para a tag <script>
, algumas páginas usam a tag para receber código Javascript que opera com dados em formato JSON de outra origem gerados dinamicamente. Esse padrão de uso é conhecido com JSONP. Requisições de JSONP não trazem JSON, mas código Javascript arbitrário. Eles são executados pelo interpretador Javascript, e não parseados pelo parser JSON.
Tem sido levantadas algumas críticas ao JSONP. Cross-Origin Resource Sharing é um método mais recente de obter dados de um servidor num domínio diferente, que lida com alguma dessas críticas.
Para ver como esse pattern funciona, considere uma requisição a uma URL que retorna um documento JSON. Um programa Javascript pode fazer a requisição dessa URL por XMLHttpRequest, por exemplo. Suponha que uma URL é http://server2.example.com/RetrieveUser?UserId=xxx
. Suponha que userID de Foo é 1234. Um navegador requerendo a URL http://server2.example.com/RetrieveUser?UserId=1234
, passando o userID de Foo, pode receber algo como:
{"Name": "Foo", "Id" : 1234, "Rank": 7}
Esses dados em formato JSON podem ser dinamicamente gerados, de acordo com os parâmetros passados na URL.
Agora imagine especificar uma URL que retorna JSON como um atributo src para um elemento <script>
. O problema como isso é que o JSON é interpretado com Javascript, mas ao invés de interpretar o conteúdo como notação literal de um objeto ele seria interpretado como um bloco e descartado como um erro de sintaxe. Mesmo que ele fosse corretamente interpretado como uma notação literal de objeto ele não poderia ser acessado por Javascript já que não estaria atribuído a uma variável.
No uso do JSONP, o atributo src no elemento <script>
é um JSON gerado dinamicamente, com uma chamada de função o encapsulando. Dessa forma, o recurso retornado continua sendo código Javascript válido, mas por ser um literal de um objeto anônimo encapsulado em uma chamada de função, o ambiente Javascript do navegador por agir nos dados retornados. Ele poderia parecer com isso:
functionCall({"Name": "Foo", "Id" : 1234, "Rank": 7});
A chamada de função é o P do JSONP - o "padding" (espaçamento) em volta do JSON puro, ou de acordo com alguns[1] o "prefixo".
<script type="text/javascript"
src="http://server2.example.com/RetrieveUser?UserId=1234&jsonp=parseResponse">
</script>
Neste exemplo, a carga recebida seria:
parseResponse({"Name": "Foo", "Id" : 1234, "Rank": 7});
Enquanto o padding (prefixo) é tipicamente o nome da função callback que é definida dentro do contexto de execução do navegador, ela pode ser uma atribuição de uma variável, trecho de if , ou qualquer outro trecho de código Javascript. A resposta a uma requisição JSONP (nominalmente, uma requisição seguindo a patter de uso do JSONP) não é JSON e não é parseada como JSON; o payload pode ser qualquer expressão Javascript arbitraria, e não precisa nem mesmo incluir JSON. Mas convencionalmente, é um fragmento Javascript que invoca uma chamada de função em algum dado formatado em JSON. Em outras palavras, o uso típico do JSONP provê acesso cross-domanin a uma API JSON existente, encapsulando o conteúdo JSON em uma chamada de função.
JSONP só faz sentido quando usado com o elemento script. Para cada novo request JSONP, o navegador precisa adicionar um novo elemento <script>
, ou reutilizar um já existente. A forma antiga, adicionando um novo elemento script, é feita via manipulação dinâmica do DOM, e é conhecida como injeção de elemento script. O elemento <script>
é injetado no DOM, com a URL do endpoint JSON desejado setado como o valor do atributo "src". Esse injeção de elemento script dinâmica é comumente feita por uma biblioteca Javascript auxiliar. jQuery e outros frameworks tem funções auxiliares; há também opções padrões. [2]
A injeção dinâmica do elemento script para uma chamada JSONP seria parecido com isso:
<script type="text/javascript"
src="http://server2.example.com/RetrieveUser?UserId=1234&jsonp=parseResponse">
</script>
Após o elemento ser injetado, o navegador interpreta o elemento, e faz um HTTP GET na URL definida no atributo "src", obtendo o conteúdo. O navegador então interpreta o payload como Javascript. Isso é tipicamente uma invocação de função.
Dessa forma, o uso do JSONP pode ser dito por permite que páginas do navegador contornem a política de mesma origem via injeção de elemento script.
Em Julho de 2005 George Jempty sugeriu uma forma opcional de atribuir uma variavel ao JSON.[3][4] A proposta original para o JSONP, onde o padding é uma função callback, parece ter sido feita por Bob Ippolito em Dezembro de 2005[5] e agora é usado por muitas aplicações Web 2.0 como o Dojo Toolkit, Google Web Toolkit,[6] e Web services.