web-dev-qa-db-fra.com

Qu'est-ce que JSONP et pourquoi a-t-il été créé?

Je comprends JSON, mais pas JSONP. Le document de Wikipedia sur JSON est (était) le premier résultat de la recherche pour JSONP. Il dit ceci:

JSONP ou "JSON avec remplissage" est une extension JSON dans laquelle un préfixe est spécifié en tant qu'argument d'entrée de l'appel lui-même.

Hein? Quel appel? Cela n'a aucun sens pour moi. JSON est un format de données. Il n'y a pas d'appel.

Le 2ème résultat de la recherche provient d'un gars nommé Remy , qui écrit ceci à propos de JSONP:

JSONP est une injection de balise de script, transmettant la réponse du serveur à une fonction spécifiée par l'utilisateur.

Je peux en quelque sorte comprendre cela, mais cela n’a toujours aucun sens.


Alors, quel est JSONP? Pourquoi a-t-il été créé (quel problème cela résout-il)? Et pourquoi devrais-je l'utiliser?


Addendum : Je viens de créer ne nouvelle page pour JSONP sur Wikipedia; il a maintenant une description claire et complète de JSONP, basée sur la réponse de jvenema .

2005
Cheeso

En fait, ce n'est pas trop compliqué ...

Disons que vous êtes sur le domaine example.com et que vous souhaitez effectuer une demande sur le domaine example.net . Pour ce faire, vous devez franchir les limites du domaine , un non-non dans la plupart des régions parcourues.

L'élément qui contourne cette limitation est les balises _<script>_. Lorsque vous utilisez une balise de script, la limitation de domaine est ignorée, mais dans des circonstances normales, vous ne pouvez pas vraiment faire avec les résultats, le script est simplement évalué.

Entrez JSONP. Lorsque vous adressez votre demande à un serveur sur lequel JSONP est activé, vous transmettez un paramètre spécial informant le serveur de votre page. De cette façon, le serveur est en mesure de bien résumer sa réponse d’une manière que votre page puisse gérer.

Par exemple, supposons que le serveur attend un paramètre appelé callback pour activer ses fonctionnalités JSONP. Votre demande ressemblerait alors à:

_http://www.example.net/sample.aspx?callback=mycallback
_

Sans JSONP, cela pourrait retourner un objet JavaScript de base, comme ceci:

_{ foo: 'bar' }
_

Cependant, avec JSONP, lorsque le serveur reçoit le paramètre "callback", le résultat est un peu différent, renvoyant quelque chose comme ceci:

_mycallback({ foo: 'bar' });
_

Comme vous pouvez le constater, il va maintenant invoquer la méthode que vous avez spécifiée. Donc, dans votre page, vous définissez la fonction de rappel:

_mycallback = function(data){
  alert(data.foo);
};
_

Et maintenant, lorsque le script est chargé, il sera évalué et votre fonction sera exécutée. Voilà, les requêtes inter-domaines!

Il convient également de noter le problème majeur de JSONP: vous perdez beaucoup de contrôle sur la demande. Par exemple, il n’existe aucun moyen "agréable" de récupérer les codes de défaillance appropriés. En conséquence, vous finissez par utiliser des minuteries pour surveiller la demande, etc., ce qui est toujours un peu suspect. La proposition de JSONRequest est une excellente solution pour autoriser les scripts entre domaines, maintenir la sécurité et permettre un contrôle approprié de la requête.

De nos jours (2015), CORS est l'approche recommandée par rapport à JSONRequest. JSONP est toujours utile pour la prise en charge des navigateurs plus anciens, mais étant donné les implications en termes de sécurité, à moins que vous n'ayez pas le choix, CORS est le meilleur choix.

1949
jvenema

JSONP est vraiment une astuce simple pour surmonter les XMLHttpRequest même politique de domaine. (Comme vous le savez, on ne peut pas envoyer AJAX (XMLHttpRequest) demande à un autre domaine.)

Donc, au lieu d'utiliser XMLHttpRequest, nous devons utiliser les balises HTML script, celles que vous utilisez habituellement pour charger des fichiers js, afin que js puisse obtenir des données d'un autre domaine. Cela semble bizarre?

La chose est - se trouve script les balises peuvent être utilisées de la même manière que XMLHttpRequest! Regarde ça:

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';

Vous vous retrouverez avec un segment script qui ressemble à ceci après le chargement des données:

<script>
{['some string 1', 'some data', 'whatever data']}
</script>

Cependant, c'est un peu gênant, car nous devons aller chercher ce tableau depuis la balise script. Donc JSONP les créateurs ont décidé que cela fonctionnerait mieux (et c'est le cas):

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback';

Notez la fonction my_callback là-bas? Ainsi, lorsque le serveur JSONP reçoit votre demande et trouve le paramètre de rappel - au lieu de renvoyer un tableau en clair, il renvoie ceci:

my_callback({['some string 1', 'some data', 'whatever data']});

Voir où le bénéfice est: Maintenant, nous avons un rappel automatique (my_callback) qui sera déclenché une fois que nous aurons obtenu les données.
C'est tout ce qu'il y a à savoir sur JSONP: il s'agit d'un rappel et de balises de script.

NOTE: Ce sont des exemples simples d'utilisation de JSONP, ce ne sont pas des scripts prêts pour la production.

exemple JavaScript de base (simple flux Twitter avec JSONP)

<html>
    <head>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
        <script>
        function myCallback(dataWeGotViaJsonp){
            var text = '';
            var len = dataWeGotViaJsonp.length;
            for(var i=0;i<len;i++){
                twitterEntry = dataWeGotViaJsonp[i];
                text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
            }
            document.getElementById('twitterFeed').innerHTML = text;
        }
        </script>
        <script type="text/javascript" src="http://Twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
    </body>
</html>

exemple de base jQuery (simple flux Twitter utilisant JSONP)

<html>
    <head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://Twitter.com/status/user_timeline/padraicb.json?count=10',
                    dataType: 'jsonp',
                    success: function(dataWeGotViaJsonp){
                        var text = '';
                        var len = dataWeGotViaJsonp.length;
                        for(var i=0;i<len;i++){
                            twitterEntry = dataWeGotViaJsonp[i];
                            text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
                        }
                        $('#twitterFeed').html(text);
                    }
                });
            })
        </script>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
    </body>
</html>


JSONP signifie JSON avec Padding. (Technique très mal nommée car elle n’a vraiment rien à voir avec ce que la plupart des gens penseraient de "rembourrage".)

688
ThatGuy

JSONP fonctionne en construisant un élément "script" (soit dans un balisage HTML, soit inséré dans le DOM via JavaScript), qui demande à un emplacement de service de données distant. La réponse est un code javascript chargé dans votre navigateur avec le nom de la fonction prédéfinie ainsi que le paramètre transmis qui correspond aux données JSON demandées. Lorsque le script s'exécute, la fonction est appelée avec les données JSON, ce qui permet à la page demandeuse de recevoir et de traiter les données.

Pour en savoir plus, visitez le site: https://blogs.sap.com/2013/07/15/secret-behind-jsonp/

extrait de code côté client

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <title>AvLabz - CORS : The Secrets Behind JSONP </title>
     <meta charset="UTF-8" />
    </head>
    <body>
      <input type="text" id="username" placeholder="Enter Your Name"/>
      <button type="submit" onclick="sendRequest()"> Send Request to Server </button>
    <script>
    "use strict";
    //Construct the script tag at Runtime
    function requestServerCall(url) {
      var head = document.head;
      var script = document.createElement("script");

      script.setAttribute("src", url);
      head.appendChild(script);
      head.removeChild(script);
    }

    //Predefined callback function    
    function jsonpCallback(data) {
      alert(data.message); // Response data from the server
    }

    //Reference to the input field
    var username = document.getElementById("username");

    //Send Request to Server
    function sendRequest() {
      // Edit with your Web Service URL
      requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
    }    

  </script>
   </body>
   </html>

Morceau serveur de PHP code

<?php
    header("Content-Type: application/javascript");
    $callback = $_GET["callback"];
    $message = $_GET["message"]." you got a response from server yipeee!!!";
    $jsonResponse = "{\"message\":\"" . $message . "\"}";
    echo $callback . "(" . $jsonResponse . ")";
?>
44
Ajain Vivek

Parce que vous pouvez demander au serveur d’ajouter un préfixe à l’objet JSON renvoyé. Par exemple

function_prefix(json_object);

afin que le navigateur puisse eval "insérer" la chaîne JSON en tant qu’expression. Cette astuce permet au serveur d’injecter du code javascript directement dans le navigateur du client, en contournant les restrictions de "même origine".

En d'autres termes, vous pouvez avoir échange de données entre domaines.


Normalement, XMLHttpRequest ne permet pas l'échange de données entre domaines directement (il faut passer par un serveur du même domaine) alors que:

<script src="some_other_domain/some_data.js&prefix=function_prefix> `on peut accéder aux données d'un domaine différent de celui de l'origine.


Il convient également de noter que même si le serveur doit être considéré comme "de confiance" avant d’essayer ce genre de "astuce", les effets secondaires d’un changement éventuel du format de l’objet, etc. peuvent être contenus. Si un function_prefix (c'est-à-dire une fonction js appropriée) est utilisé pour recevoir l'objet JSON, cette fonction peut effectuer des contrôles avant d'accepter/de poursuivre le traitement des données renvoyées.

39
jldupont

JSONP est un excellent moyen de contourner les erreurs de script inter-domaines. Vous pouvez utiliser un service JSONP uniquement avec JS sans avoir à implémenter un proxy AJAX sur le serveur.

Vous pouvez utiliser le service b1t.co pour voir comment cela fonctionne. C'est un service JSONP gratuit qui vous permet de réduire au minimum vos URL. Voici l'URL à utiliser pour le service:

http://b1t.co/Site/api/External/MakeUrlWithGet?callback= [resultsCallBack] & url = [escapedUrlToMinify]

Par exemple, l'appel http://b1t.co/Site/api/External/MakeUrlWithGet?callback=w WhateverJavascriptName&url=google.com

retournerais

whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});

Et ainsi, lorsque cela sera chargé dans votre js en tant que src, il lancera automatiquement le nomJavascript que vous devrez implémenter en tant que fonction de rappel:

function minifyResultsCallBack(data)
{
    document.getElementById("results").innerHTML = JSON.stringify(data);
}

Pour passer réellement l'appel JSONP, vous pouvez le faire de plusieurs façons (notamment en utilisant jQuery), mais voici un exemple pur en JS:

function minify(urlToMinify)
{
   url = escape(urlToMinify);
   var s = document.createElement('script');
   s.id = 'dynScript';
   s.type='text/javascript';
   s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
   document.getElementsByTagName('head')[0].appendChild(s);
}

Un exemple pas à pas et un service Web jsonp à utiliser sont disponibles à l'adresse suivante: this post

19
dardawk

Un exemple simple d'utilisation de JSONP.

client.html

    <html>
    <head>
   </head>
     body>


    <input type="button" id="001" onclick=gO("getCompany") value="Company"  />
    <input type="button" id="002" onclick=gO("getPosition") value="Position"/>
    <h3>
    <div id="101">

    </div>
    </h3>

    <script type="text/javascript">

    var elem=document.getElementById("101");

    function gO(callback){

    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://localhost/test/server.php?callback='+callback;
    elem.appendChild(script);
    elem.removeChild(script);


    }

    function getCompany(data){

    var message="The company you work for is "+data.company +"<img src='"+data.image+"'/   >";
    elem.innerHTML=message;
}

    function getPosition(data){
    var message="The position you are offered is "+data.position;
    elem.innerHTML=message;
    }
    </script>
    </body>
    </html>

server.php

  <?php

    $callback=$_GET["callback"];
    echo $callback;

    if($callback=='getCompany')
    $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";

    else
    $response="({\"position\":\"Development Intern\"})";
    echo $response;

    ?>    
12
sarath joseph

Avant de comprendre JSONP, vous devez connaître le format JSON et XML. Actuellement, le format de données le plus utilisé sur le Web est XML, mais XML est très compliqué. Cela rend les utilisateurs peu commodes pour traiter incorporé dans les pages Web.

Pour que JavaScript puisse facilement échanger des données, même en tant que programme de traitement de données, nous utilisons le libellé en fonction des objets JavaScript et avons développé un format d'échange de données simple, JSON. JSON peut être utilisé comme donnée ou comme programme JavaScript.

JSON peut être directement intégré à JavaScript. Vous pouvez les utiliser directement pour exécuter certains programmes JSON, mais en raison de contraintes de sécurité, le mécanisme Sandbox du navigateur désactive l'exécution de code JSON entre domaines.

Pour que JSON puisse être passé après l'exécution, nous avons développé un JSONP. JSONP contourne les limites de sécurité du navigateur avec la fonctionnalité de rappel JavaScript et la balise <script>.

En bref, il explique ce qu'est JSONP, quel problème il résout (quand l'utiliser).

10
Marcus Thornton

Les bonnes réponses ont déjà été données, je dois juste donner mon article sous la forme de blocs de code en javascript (j'inclurai également une solution plus moderne et meilleure pour les requêtes cross-Origin: CORS avec en-têtes HTTP):

JSONP:

1.client_jsonp.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
    dataType: "jsonp",
    success: function(data) {
        console.log(data);    
    }
});​​​​​​​​​​​​​​​​​​

2.server_jsonp.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {

    var callback = url.parse(req.url, true).query.callback || "myCallback";
    console.log(url.parse(req.url, true).query.callback);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    data = callback + '(' + JSON.stringify(data) + ');';

    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(data);
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

CORS:

3.client_cors.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/",
    success: function(data) {
        console.log(data);    
    }
});​

4.server_cors.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {
    console.log(req.headers);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    res.writeHead(200, {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
    });

    res.end(JSON.stringify(data));
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);
3
Humoyun Ahmad