«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.