About

2 мар. 2014 г.

REST Jersey 2.x: JSONP (part 3)



Один из способов кроссдоменной коммуникации это jsonp. Json with Padding. Это не формат данных, а принцип взаимодействия с внешним доменом. Даже если обращаемся в этому же домену, но к другому порту, браузер считает такой урл внешним и обычные способы взаимодействия уже не сработают.


Принцип прост - сервер возвращает данные формата json обернутые в функцию яваскрипт. callback({"data":123});
клиент добавляет на страницу тег <script>, src которого урл веб сервиса, т.о. скрипт получает яваскрипт код (callback(....)), . Затем вызывается существуюая функция callback, в которой обрабатываются принятые json данные.

Запущу мини пример с Jersey реализацией.
Tomcat 7
Netbeans 7.4
Jersey 2.4.1

Есть такой обычный сервис:

@Path(value = "/")
public class JerseyService {
    
    @GET
    @Path("/catp")
    @Produces(MediaType.APPLICATION_JSON)
    public CrazyCat getMyCat(){
        CrazyCat cat = new CrazyCat();
        cat.setEyes("blue");
        return cat;
    }
}

Сделать из него Jsonp очень просто. В Jersey 2.x появилась для этого аннотация @JSONP. В ней и задается назавание обрабатывающей функции, по умолчанию callback.
Согласно документации изменю возвращаемый тип на "application/x-javascript".
Итого:
@Path(value = "/")
public class JerseyService {
    
    @GET
    @Path("/catp")
    @JSONP
    @Produces({"application/x-javascript"})
    public CrazyCat getMyCat(){
        CrazyCat cat = new CrazyCat();
        cat.setEyes("blue");
        return cat;
    }
}

Теперь метод возващает jsonp:
callback({"eyes":"blue"})

Дело за малым, обработка на клиенте :

function callback(data) {
           var color = data["eyes"];
                var el = document.getElementById("answer");
                el.innerHTML = color;
                el.style.color = color;
            }

А так же создание скрипта:
function createScript() {
      var urlJsonp = "http://localhost:8080/JerseyJSONP/rest/catp";
                var scriptElem = document.createElement("script");
                scriptElem.type = "text/javascript";
                scriptElem.src = urlJsonp;
                document.getElementsByTagName("head")[0].appendChild(scriptElem);
   }
Теперь все готово. По нажатию на кнопку вызывается создание скрипта, получаем данные jsonp, инъектим на страницу, вызывается обработчик callback.
Вот что получилось.
Пример
Можно увидеть добавленный тег с контентом:
Инъекция скрипта

Функция не обязательно должна называться callback. Укажу в сервисе:
@JSONP(callback = "takeCat")

Теперь на странице другой обработчик:
Название функции обработчика задается в веб сервисе.

Еще способ - передать имя через параметр:
На клиенте добавляю к урл параметр с названием функции обработчика. И саму функцию:
var urlJsonp = "http://localhost:8080/JerseyJSONP/rest/catp?call=receiveCat";
 ...
 function receiveCat(data){
...
}
На сервере указывается какой параметр содержит название оборачивающей функции:
 @JSONP(queryParam = "call") 
Получаем другого обработчика:
Название функции обработчика задается на клиенте.

По теме:
Svn сего действа.
Про jsonp, а так же пример с jQ.