web-dev-qa-db-fra.com

Quelqu'un peut-il expliquer ce qu'est JSONP, en termes simples?

Je sais que JSONP est JSON avec un remplissage.

Je comprends ce qu'est JSON et comment l'utiliser avec jQuery.getJSON() . Cependant, je ne comprends pas le concept de callback lors de l'introduction de JSONP.

Quelqu'un peut-il m'expliquer comment cela fonctionne?

410
Someone

Préface:

Cette réponse a plus de six ans. Bien que les concepts et l'application de JSONP n'aient pas changé (les détails de la réponse restent valables), vous devriez cherchez à utiliser CORS si possible (c'est-à-dire votre serveur ou API le supporte, et le support du navigateur est adéquat), comme JSONP comporte des risques de sécurité inhérents .


JSONP ( JSON avec Padding ) est une méthode couramment utilisée pour contourner les règles relatives à plusieurs domaines dans les navigateurs Web. (Le navigateur ne vous autorise pas à envoyer AJAX requêtes à une page Web considérée comme étant sur un autre serveur.)

JSON et JSONP se comportent différemment sur le client et le serveur. Les requêtes JSONP ne sont pas envoyées à l'aide de XMLHTTPRequest et des méthodes de navigateur associées. A la place, une balise <script> est créée, dont la source est définie sur l'URL cible. Cette balise de script est ensuite ajoutée au DOM (normalement à l'intérieur de l'élément <head>).

Demande JSON:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    // success
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

Requête JSONP:

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);

La différence entre une réponse JSON et une réponse JSONP réside dans le fait que l'objet de réponse JSONP est transmis en tant qu'argument à une fonction de rappel.

JSON:

{ "bar": "baz" }

JSONP:

foo( { "bar": "baz" } );

C'est pourquoi vous voyez les requêtes JSONP contenant le paramètre callback, de sorte que le serveur connaisse le nom de la fonction pour encapsuler la réponse.

Cette fonction doit exister dans la portée globale au moment la balise <script> est évaluée par le navigateur (une fois le la demande est terminée).


Une autre différence à prendre en compte entre le traitement d'une réponse JSON et une réponse JSONP est que toute erreur d'analyse dans une réponse JSON peut être interceptée en encapsulant la tentative d'évaluation du responseText dans une instruction try/catch. En raison de la nature d'une réponse JSONP, les erreurs d'analyse dans la réponse entraîneront une erreur d'analyse JavaScript incompréhensible.

Les deux formats peuvent implémenter des erreurs de délai d'attente en définissant un délai d'attente avant de lancer la demande et en effaçant le délai d'attente dans le gestionnaire de réponses.


Utiliser jQuery

L’utilité d’utiliser jQuery pour effectuer des requêtes JSONP est que jQuery effectue tout le travail pour vous en arrière-plan.

Par défaut, jQuery nécessite que vous incluiez &callback=? dans l'URL de votre demande AJAX. jQuery prend la fonction success que vous spécifiez, lui attribue un nom unique et le publie dans l'étendue globale. Il remplacera ensuite le point d'interrogation ? dans &callback=? par le nom attribué.


Implémentations JSON/JSONP comparables

Ce qui suit suppose un objet de réponse { "bar" : "baz" }

JSON:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONP:

function foo(response) {
  document.getElementById("output").innerHTML = response.bar;
};

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);
764
Matt

Dites que vous avez une URL qui vous a donné des données JSON comme:

_{'field': 'value'}
_

... et vous aviez une URL similaire, sauf qu'elle utilisait JSONP, à laquelle vous aviez passé le nom de fonction de rappel 'myCallback' (généralement effectué en lui donnant un paramètre de requête appelé 'rappel', par exemple _http://example.com/dataSource?callback=myCallback_). Ensuite, il reviendrait:

_myCallback({'field':'value'})
_

... qui n'est pas simplement un objet, mais un code qui peut être exécuté. Donc, si vous définissez une fonction ailleurs dans votre page appelée myFunction et exécutez ce script, il sera appelé avec les données de l'URL.

La bonne chose à ce sujet est que vous pouvez créer une balise de script et utiliser votre URL (avec le paramètre callback) comme attribut src, et le navigateur l’exécutera. Cela signifie que vous pouvez contourner la politique de sécurité "Même origine" (car les navigateurs vous permettent d'exécuter des balises de script à partir de sources autres que le domaine de la page).

C'est ce que jQuery fait lorsque vous faites une demande ajax (en utilisant .ajax avec 'jsonp' comme valeur pour la propriété dataType.). Par exemple.

_$.ajax({
  url: 'http://example.com/datasource',
  dataType: 'jsonp',
  success: function(data) {
    // your code to handle data here
  }
});
_

Ici, jQuery prend en charge le nom de la fonction de rappel et le paramètre de requête - rendant l'API identique à d'autres appels ajax. Mais contrairement aux autres types de demandes ajax, comme mentionné, vous n'êtes pas obligé d'obtenir des données de la même origine que votre page.

73
sje397

JSONP est un moyen de contourner le navigateur règles de même origine . Comment? Comme ça:

enter image description here

Le but ici est de faire une demande à otherdomain.com et alert le nom dans la réponse. Normalement, nous ferions une requête AJAX:

$.get('otherdomain.com', function (response) {
  var name = response.name;
  alert(name);
});

Cependant, étant donné que la demande est envoyée à un domaine différent, cela ne fonctionnera pas.

Nous pouvons faire la demande en utilisant une balise <script>. <script src="otherdomain.com"></script> et $.get('otherdomain.com') donneront lieu à la même demande:

GET otherdomain.com

Q: Mais si nous utilisons la balise <script>, comment pourrions-nous accéder à la réponse? Nous devons y accéder si nous voulons alert le.

A: Euh, nous ne pouvons pas. Mais voici ce que nous pourrions faire - définissez une fonction qui utilise la réponse, puis demandez au serveur de répondre avec JavaScript qui appelle notre fonction avec la réponse comme argument.

Q: Mais que se passe-t-il si le serveur ne le fait pas pour nous et ne veut que nous renvoyer du JSON?

A: Alors nous ne pourrons pas l'utiliser. JSONP nécessite la coopération du serveur.

Q: Devoir utiliser une balise <script> est moche.

R: Des bibliothèques comme jQuery rendez-le plus agréable . Ex:

$.ajax({
    url: "http://otherdomain.com",
    jsonp: "callback",
    dataType: "jsonp",
    success: function( response ) {
        console.log( response );
    }
});

Cela fonctionne en créant dynamiquement l'élément DOM de la balise <script>.

Q: Les balises <script> ne font que des demandes GET. Que faire si nous voulons faire une demande POST?

A: Alors JSONP ne fonctionnera pas pour nous.

Q: Ce n'est pas grave, je veux juste faire une demande GET. JSONP est génial et je vais l'utiliser - merci!

A: En fait, ce n'est pas si génial. C'est vraiment juste un bidouillage. Et c'est ce n'est pas le plus sûr chose à utiliser. Maintenant que CORS est disponible, vous devez l’utiliser autant que possible.

17
Adam Zerner

J'ai trouvé un article utile qui explique également le sujet en termes clairs et faciles. Le lien est JSONP

Certains des points à noter sont:

  1. JSONP est antérieure à CORS.
  2. C’est un moyen pseudo-standard pour récupérer des données d’un domaine différent,
  3. Ses fonctionnalités CORS sont limitées (méthode GET uniquement)

Travailler est comme suit:

  1. <script src="url?callback=function_name"> est inclus dans le code html
  2. Lorsque l'étape 1 est exécutée, elle détecte une fonction portant le même nom (indiqué dans le paramètre url) en réponse.
  3. Si la fonction portant le nom indiqué existe dans le code, elle sera exécutée avec les données, le cas échéant, renvoyées en tant qu'argument de cette fonction.
2
Harshit Garg