«1. Обзор
Если вы когда-нибудь занимались веб-разработкой, вы знаете о том, что браузеры ограничивают политику одного и того же источника при работе с AJAX-запросами. Простой обзор ограничения заключается в том, что любой запрос, исходящий из другого домена, схемы или порта, не будет разрешен.
Один из способов снять это ограничение браузера при работе с данными JSON — использовать JSON с дополнением (JSON-P).
В этой статье обсуждается поддержка Spring для работы с данными JSON-P — с помощью AbstractJsonpResponseBodyAdvice.
2. JSON-P в действии
Политика одинакового происхождения не применяется к тегу \u003cscript\u003e, что позволяет загружать сценарии из разных доменов. Техника JSON-P использует это преимущество, передавая ответ JSON в качестве аргумента функции javascript.
2.1. Подготовка
В наших примерах мы будем использовать этот простой класс Company:
public class Company {
private long id;
private String name;
// standard setters and getters
}
Этот класс будет связывать параметры запроса и должен возвращаться с сервера в виде JSON-представления.
Метод Controller также является простой реализацией — он возвращает экземпляр Company:
@RestController
public class CompanyController {
@RequestMapping(value = "/companyRest",
produces = MediaType.APPLICATION_JSON_VALUE)
public Company getCompanyRest() {
Company company = new Company(1, "Xpto");
return company;
}
}
На стороне клиента мы можем использовать библиотеку jQuery для создания и отправки запроса AJAX:
$.ajax({
url: 'http://localhost:8080/spring-mvc-java/companyRest',
data: {
format: 'json'
},
type: 'GET',
...
});
Рассмотрим запрос AJAX по следующему URL-адресу:
http://localhost:8080/spring-mvc-java/companyRest
Ответ сервера будет следующим:
{"id":1,"name":"Xpto"}
Поскольку запрос был отправлен для той же схемы, домена и порта, ответ не будет получен. заблокированы, а данные JSON будут разрешены браузером.
2.2. Cross-Origin Request
При изменении URL-адреса запроса на:
http://127.0.0.1:8080/spring-mvc-java/companyRest
ответ будет заблокирован браузером из-за отправки запроса с локального хоста на 127.0.0.1, который считается другим доменом и представляет собой нарушение политики того же происхождения.
С помощью JSON-P мы можем добавить в запрос параметр обратного вызова:
http://127.1.1.1:8080/spring-mvc-java/companyRest?callback=getCompanyData
На стороне клиента это так же просто, как добавить следующие параметры в запрос AJAX:
$.ajax({
...
jsonpCallback:'getCompanyData',
dataType: 'jsonp',
...
});
getCompanyData будет функцией, вызываемой при получении ответа.
Если сервер отформатирует ответ следующим образом:
getCompanyData({"id":1,"name":"Xpto"});
браузеры не будут его блокировать, поскольку он будет рассматривать ответ как сценарий, согласованный между клиентом и сервером на основании совпадения getCompanyData в и запрос, и ответ.
3. Аннотация @ControllerAdvice
Компоненты, аннотированные @ControllerAdvice, могут помогать всем или определенному подмножеству контроллеров и используются для инкапсуляции междисциплинарного поведения, общего для разных контроллеров. Типичные шаблоны использования связаны с обработкой исключений, добавлением атрибутов в модели или регистрацией привязок.
Начиная с Spring 4.1, @ControllerAdvice может регистрировать реализации интерфейса ResponseBodyAdvice, который позволяет изменять ответ после его возврата методом контроллера, но до записи подходящим преобразователем.
4. Изменение ответа с помощью AbstractJsonpResponseBodyAdvice
Также, начиная с Spring 4.1, теперь у нас есть доступ к классу AbstractJsonpResponseBodyAdvice, который форматирует ответ в соответствии со стандартами JSON-P.
В этом разделе объясняется, как запустить базовый класс и изменить ответ, не внося никаких изменений в существующие контроллеры.
Чтобы включить поддержку Spring для JSON-P, начнем с конфигурации:
@ControllerAdvice
public class JsonpControllerAdvice
extends AbstractJsonpResponseBodyAdvice {
public JsonpControllerAdvice() {
super("callback");
}
}
Поддержка осуществляется с помощью класса AbstractJsonpResponseBodyAdvice. Ключ, переданный суперметоду, будет использоваться в URL-адресе, запрашивающем данные JSON-P.
С помощью этого совета контроллера мы автоматически конвертируем ответ в JSON-P.
5. JSON-P со Spring на практике
Имея описанную ранее конфигурацию, мы можем заставить наши REST-приложения отвечать с помощью JSON-P. В следующем примере мы будем возвращать данные компании, поэтому наш URL-адрес запроса AJAX должен выглядеть примерно так:
http://127.0.0.1:8080/spring-mvc-java/companyRest?callback=getCompanyData
В результате предыдущей настройки ответ будет выглядеть следующим образом:
getCompanyData({"id":1,"name":"Xpto"});
«
«Как уже говорилось, ответ в этом формате не будет заблокирован, несмотря на то, что он исходит из другого домена.
JsonpControllerAdvice можно легко применить к любому методу, который возвращает ответ, аннотированный с помощью @ResponseBody и ResponseEntity.
В обратном вызове должна быть функция с тем же именем, getCompanyData, для обработки всех ответов.
6. Заключение
В этой краткой статье показано, как утомительная работа по форматированию ответа для использования преимуществ JSON-P упрощается с использованием новых функций в Spring 4.1.