Primavera JSON-P com Jackson
1. Visão geral
Se você tem desenvolvido algo na web, sabe quethe same-origin policy constraint navegadores têm ao lidar com solicitações AJAX. A visão geral simples da restrição é que qualquer solicitação originada de um domínio, esquema ou porta diferente não será permitida.
Uma maneira derelax this browser restriction ao trabalhar com dados JSON - é usando JSON com preenchimento (JSON-P).
Este artigo discute o suporte do Spring para trabalhar com dados JSON-P - com a ajuda deAbstractJsonpResponseBodyAdvice.
2. JSON-P em ação
A política de mesma origem não é imposta sobre a tag<script>, permitindo que os scripts sejam carregados em domínios diferentes. A técnica JSON-P tira proveito disso, passando a resposta JSON como argumento da função javascript.
2.1. Preparação
Em nossos exemplos, usaremos esta classeCompany simples:
public class Company {
private long id;
private String name;
// standard setters and getters
}
Esta classe ligará os parâmetros de solicitação e será retornada do servidor como representação JSON.
O método Controller também é uma implementação simples - retornando a instânciaCompany:
@RestController
public class CompanyController {
@RequestMapping(value = "/companyRest",
produces = MediaType.APPLICATION_JSON_VALUE)
public Company getCompanyRest() {
Company company = new Company(1, "Xpto");
return company;
}
}
No lado do cliente, podemos usar a bibliotecajQuery para criar e enviar uma solicitação AJAX:
$.ajax({
url: 'http://localhost:8080/spring-mvc-java/companyRest',
data: {
format: 'json'
},
type: 'GET',
...
});
Considere uma solicitação AJAX no seguinte URL:
http://localhost:8080/spring-mvc-java/companyRest
A resposta do servidor seria a seguinte:
{"id":1,"name":"Xpto"}
Como a solicitação foi enviada no mesmo esquema, domínio e porta, a resposta não será bloqueada e os dados JSON serão permitidos pelo navegador.
2.2. Solicitação de origem cruzada
Alterando o URL da solicitação para:
http://127.0.0.1:8080/spring-mvc-java/companyRest
a resposta será bloqueada pelo navegador, devido à solicitação enviada delocalhost para127.0.0.1, que é considerado um domínio diferente e apresenta uma violação da política de mesma origem.
Com o JSON-P, podemos adicionar um parâmetro de retorno de chamada à solicitação:
http://127.1.1.1:8080/spring-mvc-java/companyRest?callback=getCompanyData
No lado do cliente, é tão fácil quanto adicionar os seguintes parâmetros à solicitação AJAX:
$.ajax({
...
jsonpCallback:'getCompanyData',
dataType: 'jsonp',
...
});
OgetCompanyData será a função chamada quando a resposta for recebida.
Se o servidor formatar a resposta da seguinte maneira:
getCompanyData({"id":1,"name":"Xpto"});
os navegadores não o bloquearão, pois tratarão a resposta como um script negociado e acordado entre o cliente e o servidor por causa da correspondência degetCompanyData na solicitação e na resposta.
3. @ControllerAdvice Anotação
Os beans anotados com@ControllerAdvice são capazes de auxiliar todos ou um subconjunto específico de Controladores e são usados para encapsular o comportamento de corte cruzado compartilhado entre diferentes Controladores. Os padrões de uso típicos estão relacionados aexception handling,adding attributes to models ou registro de fichários.
Starting with Spring 4.1,@ControllerAdvice é capaz de registrar as implementações da interfaceResponseBodyAdvice que permite alterar a resposta após ela ser retornada por um método do controlador, mas antes de ser escrita por um conversor adequado.
4. Alterando a resposta usandoAbstractJsonpResponseBodyAdvice
Also starting with Spring 4.1, agora temos acesso à classeAbstractJsonpResponseBodyAdvice - que formata a resposta de acordo com os padrões JSON-P.
Esta seção explica como colocar a classe base em jogo e alterar a resposta sem fazer nenhuma alteração nos controladores existentes.
Para ativar o suporte do Spring ao JSON-P, vamos começar com a configuração:
@ControllerAdvice
public class JsonpControllerAdvice
extends AbstractJsonpResponseBodyAdvice {
public JsonpControllerAdvice() {
super("callback");
}
}
O suporte é feito usando a classeAbstractJsonpResponseBodyAdvice. A chave passada no super método é a que será usada na URL que solicita dados JSON-P.
Com este conselho de controlador, convertemos automaticamente a resposta em JSON-P.
5. JSON-P com Spring na prática
Com a configuração discutida anteriormente, podemos fazer com que nossos aplicativos REST respondam com JSON-P. No exemplo a seguir, retornaremos os dados da empresa, portanto, nosso URL de solicitação AJAX deve ser algo assim:
http://127.0.0.1:8080/spring-mvc-java/companyRest?callback=getCompanyData
Como resultado da configuração anterior, a resposta terá a seguinte aparência:
getCompanyData({"id":1,"name":"Xpto"});
Conforme discutido, a resposta neste formato não será bloqueada, apesar de ser originária de um domínio diferente.
OJsonpControllerAdvice pode ser facilmente aplicado a qualquer método que retorna uma resposta anotada com@ResponseBodyeResponseEntity.
Deve haver uma função com o mesmo nome passada no retorno de chamada,getCompanyData, para lidar com todas as respostas.
6. Conclusão
Este artigo rápido mostra como um trabalho tedioso de formatar a resposta para tirar proveito do JSON-P é simplificado usando a nova funcionalidade do Spring 4.1.
A implementação dos exemplos e trechos de código pode ser encontrada nesteGitHub project.