1. Обзор
Если вы занимаетесь разработкой чего-либо в Интернете, вы знаете об ограничениях политики одного и того же источника, которые браузеры имеют при работе с запросами AJAX. Простой обзор ограничения заключается в том, что любой запрос, исходящий из другого домена, схемы или порта, не будет разрешен.
Один из способов ослабить это ограничение браузера при работе с данными JSON — использовать JSON с дополнением ( JSON-P ).
В этой статье рассматривается поддержка Spring для работы с данными JSON-P — с помощью AbstractJsonpResponseBodyAdvice
.
2. JSON-P в действии
Политика одинакового происхождения не применяется к тегу <script>
, что позволяет загружать сценарии из разных доменов. Техника 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. Запрос между источниками
Изменив 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
Bean -компоненты, аннотированные @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.
Реализацию примеров и фрагментов кода можно найти в этом проекте GitHub .