JSONP – wywoływanie zewnętrznych usług z JavaScript

Bardzo często tworzymy osobne usługi, które dostarczają jakieś dane. Pisząc aplikacje ASP.NET Web nierzadko chcemy korzystać z zewnętrznych usług, zamiast hostować dane w tym samym projekcie. Niestety może to spowodować problemy, jeśli chcemy skonsumować usługę w JavaScript, a należy ona do innej domeny.

Załóżmy, że mamy jakąś usługę REST. Dla testów posłużyłem się http://www.mocky.io. Polecam tą stronę, można generować tam własne “mocki”.  Dla tego wpisu stworzyłem mock, który zwraca następującą treść np.:

{Text:Hello world!}

Następnie na stronie, mam następujący kod JavaScript, który po prostu próbuje połączyć się z usługą i odczytać dane:

$.ajax({ url: http://www.mocky.io/v2/55772bf754441acd1b6697d0 }).done(function(data) { $(#testLabel).text(data.Text); });

Szybko przekonamy się, że wykonanie zakończy się błędem:

XMLHttpRequest cannot load http://www.mocky.io/v2/55772bf754441acd1b6697d0. No Access-Control-Allow-Origin header is present on the requested resource. Origin http://localhost:35447 is therefore not allowed access.

Przeglądarka zawsze blokuje wywołania Ajax, które próbują wywołać usługę z innej domeny (w tym przypadku localhost –> mocky.io).

Jeśli usługa zwraca dane JSON, jednym z rozwiązań może być JSONP, czyli “JavaScript Object Notation with Padding”.

Rozwiązanie wykorzystuje lukę w przeglądarkach i jest bardzo często stosowane. JSON jak wiemy, może stanowić poprawny kod JavaScript. Przeglądarki nie dopuszczają wywołań do innych domen, ale dozwolone jest załadowanie kodu, które znajduje się w innej domenie, np. poprzez <script src=’adres do zewnetrznej domeny’./>.  Z tego względu, jeśli potraktujemy zawartość zwróconą przez naszą usługę jako kod, wtedy będziemy w stanie połączyć się z nią.

Wyobraźmy sobie, że usługa zamiast zwracać {“Text”:”Hello world”}, zwraca callback({“Text:”HelloWorld”}). Dla przeglądarki jest to jak najbardziej poprawny kod i można go wykonać.

Technika jest na tyle popularna, że istnieje wiele narzędzi, które wspierają ją. Na przykład, dla powyższego wywołania ajaxowego możemy:

$.ajax({ url: http://www.mocky.io/v2/55772bf754441acd1b6697d0, dataType:jsonp }).done(function(data) { $(#testLabel).text(data.Text); });

Wystarczy dodać dataType:’jsonp’ i zobaczymy na ekranie załadowany tekst. Warto przeanalizować, jakie zapytanie jest wysłane oraz jaka odpowiedź konkretnie przychodzi. Zaglądać do logów zobaczymy, że wysyłamy:

“http://www.mocky.io/v2/55772bf754441acd1b6697d0?callback=jQuery110208627150375396013_1433874507041&_=1433874507042”.

Nie trudno spostrzec, że został dodany parametr callback, wraz z nazwą funkcji. Usługa (w tym przypadku mocky.io) rozpozna parametr callback i zwróci odpowiedź w postaci:

jQuery110208627150375396013_1433874507041({“Text”:”Hello world!”});

Następnie jQuery wykona daną funkcję, która tak naprawdę odczyta parametr wejściowy i przekaże ją do funkcji done. Innymi słowy, kod zwrócony przez usługę zostanie wykonany w formie funkcji callback’a, który wywołuje “done” przekazując dostarczony parametr, który stanowi dane zwrócone przez usługę.

Warto zwrócić uwagę, że usługa musi rozpoznawać parametr callback i zwracać zawartość w formie callback(dane) zamiast po prostu czyste dane. Domyślnie WebAPI nie zrobi tego za nas, ale w przyszłym wpisie pokażę w jaki sposób to osigągnąć. Czyste dane JSON zwracane przez usługi, stanowią poprawny kod JavaScript, ale nic z nimi nie możemy zrobić. Jeśli opleciemy je w funkcję, umożliwi nam to przechwycenie tych danych poprzez implementację danej funkcji i odczytanie parametrów wejściowych.

4 thoughts on “JSONP – wywoływanie zewnętrznych usług z JavaScript”

Leave a Reply

Your email address will not be published.