JQuery olmadan Javascript'ten JSONP isteği nasıl yapılır?


122

JQuery veya başka bir harici kitaplık kullanmadan JavaScript'te etki alanları arası JSONP isteğinde bulunabilir miyim? JavaScript'in kendisini kullanmak ve ardından verileri ayrıştırıp onu kullanabilmem için bir nesne yapmak istiyorum. Harici bir kitaplık kullanmak zorunda mıyım? Değilse nasıl yapabilirim?


Yanıtlar:


151
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

2
Wikipedia'dan JSONP ile uğraşmak için kullanılabilecek bir JSBin burada . Bu cevapta referans alınmıştır .
rkagerer

1
Yanıtın şu biçimde olması gerektiğine dikkat foo(payload_of_json_data)çekmeye değer olduğunu düşünüyorum: Betik etiketine yüklendiğinde, zaten bir javascript nesnesi olarak yük ile foo işlevini çağırması ve ayrıştırmaya gerek olmaması fikri.
Ahtapot

@WillMunn Bunun JSONP ile yapılabileceğini sanmıyorum. Bu, CORS öncesi günlerden kalma bir hack. Başlıkları ne için ayarlamanız gerekiyor? Sunucunun özellikle JSONP isteklerini kabul etmesi gerekir, bu nedenle mantıklı bir şekilde hizmet verecek şekilde ayarlanmalıdır.
Matt Ball

haklısın, bazı api belgelerini yanlış okudum, jsonp özürlerini kullanırken istediğimi yapmak için özel bir sorgu parametresi var.
Will Munn

@WillMunn endişelenmenize gerek yok. Çözebildiğine sevindim!
Matt Ball

37

Hafif örnek (onSuccess ve onTimeout desteği ile). İhtiyacınız olursa, geri arama adını URL içinde iletmeniz gerekir.

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;
})();

Örnek kullanım:

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

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


29

JSONP nedir?

Jsonp ile hatırlanması gereken önemli şey, aslında bir protokol veya veri türü olmamasıdır. Bu , anında bir komut dosyası yüklemenin ve sayfaya tanıtılan komut dosyasını işlemenin bir yoludur . JSONP ruhuna uygun olarak bu, sunucudan istemci uygulamasına / komut dosyasına yeni bir javascript nesnesi tanıtmak anlamına gelir.

JSONP ne zaman gereklidir?

Bir alanın aynı sayfadaki diğerinden eşzamansız olarak verilere erişmesine / işlemesine izin verme yöntemidir. Öncelikle, bir XHR (ajax) isteği ile ortaya çıkabilecek CORS (Çapraz Kaynak Paylaşımı) kısıtlamalarını geçersiz kılmak için kullanılır. Komut dosyası yüklemeleri, CORS kısıtlamalarına tabi değildir.

Nasıl oldu

Sunucudan yeni bir javascript nesnesinin tanıtılması birçok şekilde uygulanabilir, ancak en yaygın uygulama, sunucunun bir 'geri arama' işlevinin yürütülmesini gerekli nesnenin kendisine iletilmesiyle gerçekleştirmesidir. Geri çağırma işlevi, istemcide zaten kurduğunuz ve komut dosyasının kendisine iletilen verileri işlemek için komut dosyasının yüklendiği noktada çağrıları yüklediğiniz bir işlevdir .

Misal:

Birinin evindeki tüm öğeleri kaydeden bir uygulamam var. Uygulamam kuruldu ve şimdi ana yatak odasındaki tüm öğeleri almak istiyorum.

Başvurum açık app.home.com. Verileri yüklemem gereken apiler açık api.home.com.

Sunucu açıkça buna izin verecek şekilde ayarlanmadıkça, bu verileri yüklemek için ajax kullanamam, çünkü ayrı alt alanlardaki sayfalar bile XHR CORS kısıtlamalarına tabidir.

İdeal olarak, x alanı XHR'ye izin vermek için bir şeyler ayarlayın

İdeal olarak, api ve uygulama aynı etki alanında olduğundan, üstbilgileri ayarlamak için erişimim olabilir api.home.com. Access-Control-Allow-Origin: Yaparsam, erişim sağlayan bir başlık öğesi ekleyebilirim app.home.com. Başlığın aşağıdaki gibi ayarlandığını varsayarsak Access-Control-Allow-Origin: "http://app.home.com", bu JSONP'yi kurmaktan çok daha güvenlidir. Bunun nedeni app.home.com, CORS'a tüm internete erişim api.home.comizni api.home.comvermeden istediği her şeyi alabilmesidir .

Yukarıdaki XHR çözümü mümkün değildir. JSONP'yi kur İstemci komut dosyamda: JSONP çağrısı yaptığımda sunucudan gelen yanıtı işlemek için bir işlev kuruyorum. :

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

Sunucunun bir mini betiğe benzer bir görünüme kavuşması için ayarlanması gerekecektir. "processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"Böyle bir şey //api.home.com?getdata=room&room=main_bedroomçağrıldığında böyle bir dizgeyi döndürecek şekilde tasarlanmış olabilir .

Ardından müşteri aşağıdaki gibi bir komut dosyası etiketi oluşturur:

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

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

Bu, betiği yükler ve hemen window.processJSONPResponse()sunucu tarafından yazılmış / echo / yazdırılmış olarak çağırır . İşleve parametre olarak aktarılan veriler artık dataFromServeryerel değişkende saklanır ve bununla ihtiyacınız olan her şeyi yapabilirsiniz.

Temizlemek

Müşteri verilere sahip olduğunda, yani. komut dosyası DOM'a eklendikten hemen sonra komut dosyası öğesi DOM'dan kaldırılabilir:

script.parentNode.removeChild(script);

2
Çok teşekkürler, bu bana projemde çok yardımcı oldu. Küçük bir sorun: Aldım SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data. : Verilere tek tırnak ekledikten sonra, her şey iyi, bu yüzden çalıştı"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"
Hein van Dyke

17

Anladığım kadarıyla aslında JSONP, sooo ile komut dosyası etiketleri kullanıyorsunuz ...

İlk adım, JSON'u işleyecek işlevinizi oluşturmaktır:

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

Bu işleve küresel düzeyde erişilebilir olduğundan emin olun.

Ardından, DOM'a bir komut dosyası öğesi ekleyin:

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

Komut dosyası, API sağlayıcısının oluşturduğu JavaScript'i yükleyecek ve çalıştıracaktır.


2
Herkese teşekkürler. Bazı verileri aramak için internet üzerinden fırlattım ve sonra onunla bir şeyler yaptım. Yanıt verilerinde eval () kullandım, bu da nesne dizisiyle başa çıkmama yardımcı oldu (sanırım). {Sınırlı beyin gücümle ayrıştırmayı çözen bir ayıydı ama sonunda ondan çıkarılan değeri aldım}. Fantastik.
Dave

@Dave @Matt Belki ben JSONP üzerinde bulanık, ama ihtiyacınız olmamalı evalveya parseherhangi bir şey ya. Tarayıcının çalıştırabileceği JavaScript almalısınız, değil mi?
sdleihssirhc

Benim hatam, karışıklık için özür dilerim. Diziden bir şeyi (değer? Özellik?) Almaya çalışmak başımı döndürüyordu (İç içe geçme, geri arama, dizi, öğe, nesne, dizge, değer, küme parantezleri, parantezler ...). Eval kullanımımı kaldırdım ve hala istediğim diziden (nesne? Öğe?) Özelliği (değer?) Alıyorum.
Dave

10

jsonp'yi aşağıdaki gibi kullanma şeklim:

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)
    });
}

sonra şu şekilde 'jsonp' yöntemini kullanın:

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

referans:

JsonP kullanarak JavaScript XMLHttpRequest

http://www.w3ctech.com/topic/721 (Promise'ın kullanım şekli hakkında konuşun)


1
atamaları sonlandırın script.src = src; ekle ';' tüm görevlerin sonuna
chdev77


5
/**
 * 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);
  });
})();

Kullanım örneği:

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

1
window[callback] = nullİşlevin çöplerin toplanmasına izin vermeyi unutmayın .
Sukima

3

Bunu olabildiğince basit bir şekilde ele almak için bir kütüphane yazdım. Harici yapmaya gerek yok, bu sadece bir işlevi. Diğer bazı seçeneklerin aksine, bu komut dosyası kendisinden sonra temizler ve çalışma zamanında daha fazla istekte bulunmak için genelleştirilmiştir.

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

JQuery olmadan arama JavaScriptyapmak için aşağıdaki örneği bulun JSONP:

Ayrıca, GitHubreferans için depoma başvurabilirsiniz .

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);
    }
}


0
/**
 * 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' );

Neden window.document.getElementsByTagName('script')[0];ve değil document.body.appendChild(…)?
Sukima

Olmamalı logAPIayarlanmalıdır nullçöp toplama üzerinde yapılabilir bunu yaptığı zaman?
Sukima

0

ES6'yı NPM ile kullanıyorsanız, düğüm modülü "fetch-jsonp" deneyebilirsiniz. Fetch API Normal bir XHR çağrısı olarak bir JsonP çağrısı yapmak için destek sağlar.

Önkoşul: isomorphic-fetchyığında düğüm modülü kullanıyor olmalısın .


0

Sobstel'in güzel cevabının bir ES6 sürümünü yapıştırıyorum:

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)
    })
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.