JSONP – sposób na obejście Same-origin policy

Nazwa JSONP  pochodzi od JSON with Padding. Jest to rozwiązanie pozwalające obejść zabezpieczenie Same-origin policy (SOP). Opiera się ono na wyjątku, w którym zewnętrze zasoby możemy  załadować przez znacznik <script/>.

Choć to rozwiązanie nie jest już potrzebne dzięki CORS to czasami starsze rozwiązania nie mają ustawionych odpowiednich nagłówków (niezbędnych przy Cross-Origin Resource Sharing), a nie mając dostępu do tego API musimy w inny sposób sobie poradzić. Tutaj przychodzi JSONP, które jest zaimplementowane również w jQuery.

Proste API w PHP

Wyobraźmy sobie, że pod adresem http://www.bogolubow.com/api/datetime.php znajduje się API, które przekazuje aktualną datę i czas. Po wpisaniu tego URL do paska adresu przeglądarki moglibyśmy zobaczyć poniższy tekst:

{"date": "2017-04-12", "time": "10:24:04"}

Aby osiągnąć taki efekt musielibyśmy utworzyć plik datetime.php z poniższym kodem:

<?php 

$json = '{"date": "'. date('Y-m-d') .'", "time": "'. date('H:i:s') .'"}';
echo $json;

W linii 3 zapisuje dane jako string do zmiennej $json. Ostatnia tj. 4 linia wyświetla ciąg znaków zawarty w zmiennej $json.

Implementacja JSONP

Teraz wystarczy dodanie znacznika <script/> do naszej strony np. http://www.webperfection.pl/jsonp.html:

<script src="http://www.bogolubow.com/api/datetime.php"></script>

Co prawda mamy błąd składni (to nie prawidłowy kod JavaScript) to dane odebraliśmy z zewnętrznego zasobu. Teraz jeśli odpowiednio przygotujemy dane zwracane przez datetime.php to być może w konsoli nie wyświetli się błąd.

Zmieńmy kod PHP w poniższy sposób:

<?php 

$json = '{"date": "'. date('Y-m-d') .'", "time": "'. date('H:i:s') .'"}';
echo 'jsonp('.$json.')';

To spowoduje, że wysyłane dane będą wyglądać w taki sposób:

jsonp({"date": "2017-04-12", "time": "23:30:16"})

Jeśli zajrzysz do konsoli plik jsonp.html wyrzuci błąd tego typu: Uncaught ReferenceError: jsonp is not defined.

Co się stanie jeśli zdefiniujemy jsonp? Zauważmy, że jsonp zawiera wywołanie więc spróbujmy zdefiniować tą funkcję wraz z jednym parametrem. Teraz mamy już dwa skrypty podpięte pod jsonp.html:

<script>
function jsonp(param) {
    console.log(param);
}
</script> 
<script src="http://www.bogolubow.com/api/datetime.php"></script>

Teraz zamiast błędu w konsoli mamy obiekt. Możemy wykorzystać dane przesłane z zewnętrznego zasobu.

Moglibyśmy bardziej skomplikować nasz kod w pliku datetime.php, gdzie dodatkowo moglibyśmy przesyłać jak ma się nazywać nasza funkcja za pomocą metody GET, np.:

<?php 

$json = '{"date": "'. date('Y-m-d') .'", "time": "'. date('H:i:s') .'"}';
echo $_GET['callback'].'('.$json.')';

W ostatniej linii odbieramy dane przesłane metodą GET o odpowiednim kluczu.

Teraz nasz kod w pliku jsonp.html mógłby wyglądać w taki sposób:

<script>
function fn(param) {
    console.log(param.date, param.time);
}
</script> 
<script src="http://www.bogolubow.com/api/datetime.php?callback=fn"></script>

Nasz kod jest bardziej elastyczny. Definiujemy jak ma się nazywać funkcja, która będzie odbierać dane z zewnętrznego zasobu.

JSONP w jQuery

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
    $.ajax({
        url: 'http://www.bogolubow.com/api/datetime.php',
        dataType: 'jsonp',
    }).done(function(res){
        console.log(res)
    }).fail(function(error){
        console.log(error);
    })
</script>

jQuery automatycznie tworzy element <script/> i definiuje atrybut src. Do adresu dodaje parametr GET o kluczu callback, dzięki czemu wiadomo jaka funkcja odbierze dane. W moim przypadku adres do API wyglądał w taki sposób:

datetime.php?callback=jQuery321021464946746158908_1492034568112&_=1492034568113

Natomiast w konsoli pojawił się obiekt, który został zwrócony przez API.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*

*

seventeen + 18 =