web-dev-qa-db-fra.com

Comment faire une demande JSONP à partir de Javascript sans JQuery?

Puis-je effectuer une requête JSONP inter-domaines en JavaScript sans utiliser jQuery ou une autre bibliothèque externe? J'aimerais utiliser JavaScript lui-même, puis analyser les données et en faire un objet pour pouvoir les utiliser. Dois-je utiliser une bibliothèque externe? Si non, comment puis-je le faire?

116
Dave
function foo(data)
{
    // do stuff with JSON
}

var script = document.createElement('script');
script.src = '//example.com/path/to/jsonp?callback=foo'

document.getElementsByTagName('head')[0].appendChild(script);
// or document.head.appendChild(script) in modern browsers
147
Matt Ball

Exemple léger (avec prise en charge de onSuccess et onTimeout). Vous devez transmettre le nom de rappel dans l'URL si vous en avez besoin.

var $jsonp = (function(){
  var that = {};

  that.send = function(src, options) {
    var callback_name = options.callbackName || 'callback',
      on_success = options.onSuccess || function(){},
      on_timeout = options.onTimeout || function(){},
      timeout = options.timeout || 10; // sec

    var timeout_trigger = window.setTimeout(function(){
      window[callback_name] = function(){};
      on_timeout();
    }, timeout * 1000);

    window[callback_name] = function(data){
      window.clearTimeout(timeout_trigger);
      on_success(data);
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.src = src;

    document.getElementsByTagName('head')[0].appendChild(script);
  }

  return that;
})();

Exemple d'utilisation:

$jsonp.send('some_url?callback=handleStuff', {
    callbackName: 'handleStuff',
    onSuccess: function(json){
        console.log('success!', json);
    },
    onTimeout: function(){
        console.log('timeout!');
    },
    timeout: 5
});

Sur GitHub: https://github.com/sobstel/jsonp.js/blob/master/jsonp.js

35
sobstel

Qu'est-ce que JSONP?

La chose importante à retenir avec jsonp est qu’il ne s’agit ni d’un protocole ni d’un type de données. C'est juste une façon de charger un script à la volée et de traiter le script introduit dans la page. Dans l'esprit de JSONP, cela signifie introduire un nouvel objet javascript du serveur dans l'application/le script client.

Quand JSONP est-il nécessaire?

C'est une méthode permettant à un domaine d'accéder/de traiter les données d'un autre dans la même page de manière asynchrone. Il est principalement utilisé pour remplacer les restrictions CORS (Cross Origin Resource Sharing) qui se produiraient avec une demande XHR (ajax). Les charges de script ne sont pas soumises aux restrictions CORS.

Comment est-il fait

L'introduction d'un nouvel objet javascript à partir du serveur peut être implémentée de plusieurs manières, mais le plus souvent, le serveur implémente l'exécution d'une fonction de rappel avec l'objet requis. La fonction de rappel est simplement une fonction que vous avez déjà configurée sur le client et que vous chargez le script au point le script chargé de traiter les données qui lui sont transmises.

Exemple:

J'ai une application qui enregistre tous les objets chez quelqu'un. Mon application est configurée et je souhaite maintenant récupérer tous les éléments de la chambre principale. 

Mon application est sur app.home.com. Les adresses dont je dois charger les données sont sur api.home.com

À moins que le serveur ne soit explicitement configuré pour l'autoriser, je ne peux pas utiliser ajax pour charger ces données, car même les pages de sous-domaines distincts sont soumises à des restrictions XHR CORS.

Idéalement, configurez les éléments de manière à autoriser XHRX-domain

Idéalement, comme l’API et l’application se trouvent sur le même domaine, je pourrais peut-être configurer les en-têtes sur api.home.com. Si je le fais, je peux ajouter un élément d'en-tête Access-Control-Allow-Origin: donnant accès à app.home.com. En supposant que l'en-tête soit configuré comme suit: Access-Control-Allow-Origin: "http://app.home.com", cela est beaucoup plus sécurisé que la configuration de JSONP. Ceci est dû au fait que app.home.com peut obtenir tout ce qu'il veut de api.home.com sans que api.home.com donne à CORS l’accès à Internet au complet.

La solution XHR ci-dessus n'est pas possible. Configurer JSONP Sur mon script client: J'ai configuré une fonction pour traiter la réponse du serveur lorsque je passe l'appel JSONP.:

function processJSONPResponse(data) {
    var dataFromServer = data;
}

Le serveur devra être configuré pour renvoyer un mini script ressemblant à "processJSONPResponse({"room":"main bedroom","items":["bed","chest of drawers"]});". Il pourrait être conçu pour renvoyer une telle chaîne si quelque chose comme //api.home.com?getdata=room&room=main_bedroom est appelé.

Ensuite, le client configure une balise de script en tant que telle:

var script = document.createElement('script');
script.src = '//api.home.com?getdata=room&room=main_bedroom';

document.querySelector('head').appendChild(script);

Ceci charge le script et appelle immédiatement window.processJSONPResponse() comme écrit/echo/imprimé par le serveur. Les données transmises en tant que paramètre de la fonction sont maintenant stockées dans la variable locale dataFromServer et vous pouvez en faire ce dont vous avez besoin.

Nettoyer

Une fois que le client a les données, à savoir. immédiatement après l'ajout du script au DOM, l'élément de script peut être supprimé du DOM:

script.parentNode.removeChild(script);
26
dewd

Je crois comprendre que vous utilisez en fait des balises de script avec JSONP, sooo ...

La première étape consiste à créer votre fonction qui gérera le JSON:

function hooray(json) {
    // dealin wit teh jsonz
}

Assurez-vous que cette fonction est accessible au niveau mondial.

Ensuite, ajoutez un élément de script au DOM:

var script = document.createElement('script');
script.src = 'http://domain.com/?function=hooray';
document.body.appendChild(script);

Le script charge le code JavaScript créé par le fournisseur d'API et l'exécute.

17
sdleihssirhc

la façon dont j'utilise jsonp comme ci-dessous:

function jsonp(uri) {
    return new Promise(function(resolve, reject) {
        var id = '_' + Math.round(10000 * Math.random());
        var callbackName = 'jsonp_callback_' + id;
        window[callbackName] = function(data) {
            delete window[callbackName];
            var ele = document.getElementById(id);
            ele.parentNode.removeChild(ele);
            resolve(data);
        }

        var src = uri + '&callback=' + callbackName;
        var script = document.createElement('script');
        script.src = src;
        script.id = id;
        script.addEventListener('error', reject);
        (document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
    });
}

utilisez ensuite la méthode 'jsonp' comme ceci:

jsonp('http://xxx/cors').then(function(data){
    console.log(data);
});

référence:

JavaScript XMLHttpRequest à l'aide de JsonP

http://www.w3ctech.com/topic/721 (discussion sur le mode d'utilisation de Promise)

8
derek

J'ai une pure bibliothèque javascript pour le faire https://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js

Jetez-y un coup d'œil et dites-moi si vous avez besoin d'aide pour utiliser ou comprendre le code. 

Btw, vous avez un exemple d'utilisation simple ici: http://robertodecurnex.github.com/J50Npi/

6
robertodecurnex
/**
 * Loads data asynchronously via JSONP.
 */
const load = (() => {
  let index = 0;
  const timeout = 5000;

  return url => new Promise((resolve, reject) => {
    const callback = '__callback' + index++;
    const timeoutID = window.setTimeout(() => {
      reject(new Error('Request timeout.'));
    }, timeout);

    window[callback] = response => {
      window.clearTimeout(timeoutID);
      resolve(response.data);
    };

    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.src = url + (url.indexOf('?') === -1 ? '?' : '&') + 'callback=' + callback;
    document.getElementsByTagName('head')[0].appendChild(script);
  });
})();

Exemple d'utilisation:

const data = await load('http://api.github.com/orgs/kriasoft');
5
Konstantin Tarkus

J'ai écrit une bibliothèque pour gérer cela, aussi simplement que possible. Pas besoin de le rendre externe, c'est juste une fonction. Contrairement à d'autres options, ce script nettoie lui-même et est généralisé pour les requêtes ultérieures au moment de l'exécution. 

https://github.com/Fresheyeball/micro-jsonp

function jsonp(url, key, callback) {

    var appendParam = function(url, key, param){
            return url
                + (url.indexOf("?") > 0 ? "&" : "?")
                + key + "=" + param;
        },

        createScript = function(url, callback){
            var doc = document,
                head = doc.head,
                script = doc.createElement("script");

            script
            .setAttribute("src", url);

            head
            .appendChild(script);

            callback(function(){
                setTimeout(function(){
                    head
                    .removeChild(script);
                }, 0);
            });
        },

        q =
            "q" + Math.round(Math.random() * Date.now());

    createScript(
        appendParam(url, key, q), function(remove){
            window[q] =
                function(json){
                    window[q] = undefined;
                    remove();
                    callback(json);
                };
        });
}
2
Fresheyeball

Veuillez trouver ci-dessous l'exemple JavaScript pour effectuer un appel JSONP sans JQuery:

En outre, vous pouvez vous référer à mon référentiel GitHub.

https://github.com/shedagemayur/JavaScriptCode/tree/master/jsonp

window.onload = function(){
    var callbackMethod = 'callback_' + new Date().getTime();

    var script = document.createElement('script');
    script.src = 'https://jsonplaceholder.typicode.com/users/1?callback='+callbackMethod;

    document.body.appendChild(script);

    window[callbackMethod] = function(data){
        delete window[callbackMethod];
        document.body.removeChild(script);
        console.log(data);
    }
}

1
Mayur Shedage
/**
 * Get JSONP data for cross-domain AJAX requests
 * @private
 * @link http://cameronspear.com/blog/exactly-what-is-jsonp/
 * @param  {String} url      The URL of the JSON request
 * @param  {String} callback The name of the callback to run on load
 */
var loadJSONP = function ( url, callback ) {

    // Create script with url and callback (if specified)
    var ref = window.document.getElementsByTagName( 'script' )[ 0 ];
    var script = window.document.createElement( 'script' );
    script.src = url + (url.indexOf( '?' ) + 1 ? '&' : '?') + 'callback=' + callback;

    // Insert script tag into the DOM (append to <head>)
    ref.parentNode.insertBefore( script, ref );

    // After the script is loaded (and executed), remove it
    script.onload = function () {
        this.remove();
    };

};

/** 
 * Example
 */

// Function to run on success
var logAPI = function ( data ) {
    console.log( data );
}

// Run request
loadJSONP( 'http://api.petfinder.com/shelter.getPets?format=json&key=12345&shelter=AA11', 'logAPI' );
0
Chris Ferdinandi

Si vous utilisez ES6 avec NPM, vous pouvez essayer le module de noeud "fetch-jsonp" . Fetch API Fournit une assistance pour passer un appel JsonP en tant qu'appel XHR normal.

Condition préalable: vous devriez utiliser le module de noeud isomorphic-fetch dans votre pile.

Il suffit de coller une version ES6 de la réponse Nice de sobstel:

send(someUrl + 'error?d=' + encodeURI(JSON.stringify(json)) + '&callback=c', 'c', 5)
    .then((json) => console.log(json))
    .catch((err) => console.log(err))

function send(url, callback, timeout) {
    return new Promise((resolve, reject) => {
        let script = document.createElement('script')
        let timeout_trigger = window.setTimeout(() => {
            window[callback] = () => {}
            script.parentNode.removeChild(script)
            reject('No response')
        }, timeout * 1000)

        window[callback] = (data) => {
            window.clearTimeout(timeout_trigger)
            script.parentNode.removeChild(script)
            resolve(data)
        }

        script.type = 'text/javascript'
        script.async = true
        script.src = url

        document.getElementsByTagName('head')[0].appendChild(script)
    })
}
0
just_user