JQuery없이 Javascript에서 JSONP 요청을 만드는 방법은 무엇입니까?


122

jQuery 또는 기타 외부 라이브러리를 사용하지 않고 JavaScript에서 교차 도메인 JSONP 요청을 할 수 있습니까? JavaScript 자체를 사용하고 데이터를 구문 분석하여 사용할 수 있도록 객체로 만들고 싶습니다. 외부 라이브러리를 사용해야합니까? 그렇지 않다면 어떻게해야합니까?


답변:


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의 JSONP 를 조작하는 데 사용할 수있는 JSBin입니다 . 이 답변 에서 참조되었습니다 .
rkagerer 2013 년

1
응답이 형식이어야한다는 점을 지적 할 가치가 있다고 생각합니다 foo(payload_of_json_data). 스크립트 태그에로드 될 때 이미 페이로드가있는 foo 함수를 자바 스크립트 객체로 호출하고 파싱이 필요하지 않다는 생각입니다.
Octopus

@WillMunn JSONP로 할 수 있다고 생각하지 않습니다. CORS 이전 시대의 해킹입니다. 헤더를 설정하려면 무엇을해야합니까? 서버는 특히 JSONP 요청을 수락해야하므로 정상적인 방식으로 제공되도록 설정해야합니다.
Matt Ball

맞아요, 일부 API 문서를 잘못 읽었습니다. jsonp 응용 프로그램을 사용할 때 원하는 작업을 수행하는 특수 쿼리 매개 변수가 있습니다.
윌 Munn

@WillMunn 걱정 마세요. 정리할 수있어서 다행입니다!
Matt Ball

37

간단한 예제 (onSuccess 및 onTimeout 지원 포함). 필요한 경우 URL 내에서 콜백 이름을 전달해야합니다.

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

샘플 사용법 :

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

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


29

JSONP 란 무엇입니까?

jsonp에서 기억해야 할 중요한 점은 실제로 프로토콜이나 데이터 유형이 아니라는 것입니다. 즉석 에서 스크립트 를 로드 하고 페이지에 도입 된 스크립트를 처리 하는 방법입니다 . JSONP의 정신에서 이것은 서버에서 클라이언트 애플리케이션 / 스크립트로 새로운 javascript 객체를 도입하는 것을 의미합니다.

JSONP는 언제 필요합니까?

하나의 도메인이 같은 페이지에있는 다른 도메인의 데이터를 비동기 적으로 액세스 / 처리하도록 허용하는 한 가지 방법입니다. 주로 XHR (ajax) 요청에서 발생하는 CORS (Cross Origin Resource Sharing) 제한을 재정의하는 데 사용됩니다. 스크립트로드에는 CORS 제한이 적용되지 않습니다.

어떻게하나요

서버에서 새로운 자바 스크립트 객체를 도입하는 것은 여러 가지 방법으로 구현할 수 있지만 가장 일반적인 방법은 서버가 필요한 객체를 전달하여 '콜백'함수의 실행을 구현하는 것입니다. 콜백 기능을 사용하면 클라이언트에 이미 설정 한 단지 기능입니다 스크립트가 이 시점에서 호출로드 스크립트 로드가에 전달 된 데이터를 처리 할 수 있습니다.

예:

누군가의 집에있는 모든 항목을 기록하는 응용 프로그램이 있습니다. 내 응용 프로그램이 설정되었으며 이제 주 침실에있는 모든 항목을 검색하려고합니다.

내 응용 프로그램은에 app.home.com있습니다. 데이터를로드하는 데 필요한 API가 켜져 api.home.com있습니다.

서버가이를 허용하도록 명시 적으로 설정되어 있지 않으면 별도의 하위 도메인에있는 페이지에도 XHR CORS 제한이 적용되므로이 데이터를로드하는 데 ajax를 사용할 수 없습니다.

이상적으로는 x-domain XHR을 허용하도록 설정하십시오.

이상적으로는 API와 앱이 동일한 도메인에 있으므로 .NET에서 헤더를 설정할 수있는 액세스 권한이있을 수 있습니다 api.home.com. 그렇게하면에 Access-Control-Allow-Origin: 대한 액세스 권한을 부여 하는 헤더 항목을 추가 할 수 있습니다 app.home.com. 헤더가 다음과 같이 설정되었다고 가정하면 Access-Control-Allow-Origin: "http://app.home.com"JSONP를 설정하는 것보다 훨씬 안전합니다. CORS가 전체 인터넷에 액세스 하지 않고도 app.home.com원하는 모든 것을 얻을 수 있기 때문 입니다.api.home.comapi.home.com

위의 XHR 솔루션은 불가능합니다. 클라이언트 스크립트에서 JSONP 설정 : JSONP 호출을 할 때 서버의 응답을 처리하는 함수를 설정했습니다 . :

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

서버는 다음과 같은 미니 스크립트를 반환하도록 설정 "processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"되어야 //api.home.com?getdata=room&room=main_bedroom합니다. 유사한 것이 호출 되면 그러한 문자열을 반환하도록 설계되었을 수 있습니다 .

그런 다음 클라이언트는 다음과 같이 스크립트 태그를 설정합니다.

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

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

이것은 스크립트를로드 window.processJSONPResponse()하고 서버에 의해 쓰여진 / 에코 / 인쇄 된대로 즉시 호출 합니다. 함수에 매개 변수로 전달 된 데이터는 이제 dataFromServer로컬 변수에 저장되며 필요한 모든 작업을 수행 할 수 있습니다.

정리

클라이언트가 데이터를 가지면, 즉. 스크립트가 DOM에 추가 된 직후 DOM에서 스크립트 요소를 제거 할 수 있습니다.

script.parentNode.removeChild(script);

2
감사합니다. 이것은 제 프로젝트에 많은 도움이되었습니다. 사소한 문제 :을 받았습니다 SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data. : 데이터에 작은 따옴표를 추가 한 후, 다 잘, 그래서 일"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"
하인 반 다이크

17

내 이해는 실제로 JSONP와 함께 스크립트 태그를 사용한다는 것입니다.

첫 번째 단계는 JSON을 처리 할 함수를 만드는 것입니다.

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

이 기능이 글로벌 수준에서 액세스 가능한지 확인하십시오.

다음으로, 스크립트 요소를 DOM에 추가합니다.

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

스크립트는 API 공급자가 빌드 한 JavaScript를로드하고 실행합니다.


2
모두에게 감사합니다. 일부 데이터를 찾아 인터넷을 통해 촬영 한 후 뭔가를합니다. 응답 데이터에 eval ()을 사용하여 객체를 처리하는 데 도움이되었습니다. {내 제한된 두뇌 능력으로 분석하는 것을 이해하는 곰 이었지만 마침내 그 가치를 얻었습니다}. 환상적입니다.
Dave

@ 데이브 @ 매트는 어쩌면 나는 JSONP에 퍼지,하지만 당신은 필요가 없습니다 eval또는 parse아무것도 나. 브라우저가 바로 실행할 수있는 JavaScript를 얻어야합니다.
sdleihssirhc

죄송합니다. 혼란을 드려 죄송합니다. 배열에서 사물 (값? 속성?)을 가져 오려고하면 머리가 돌고있었습니다 (중첩, 콜백, 배열, 요소, 개체, 문자열, 값, 중괄호, 대괄호 ...). eval 사용을 제거했지만 원하는 배열 (개체? 요소?)에서 속성 (값?)을 여전히 얻었습니다.
Dave

10

아래와 같이 jsonp를 사용하는 방법 :

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

그런 다음 다음과 같이 'jsonp'메소드를 사용하십시오.

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

참고:

JsonP를 사용한 JavaScript XMLHttpRequest

http://www.w3ctech.com/topic/721(Promise 사용 방법에 대해 이야기)


1
할당 종료 script.src = src; ';'추가 모든 할당의 끝까지
chdev77

6

https://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js 를 수행하는 순수한 자바 스크립트 라이브러리가 있습니다.

그것을 살펴보고 코드를 사용하거나 이해하는 데 도움이 필요하면 알려주십시오.

Btw, 여기에 간단한 사용 예가 있습니다. http://robertodecurnex.github.com/J50Npi/


6
귀하의 솔루션은 내 사용 사례에 비해 너무 간단했기 때문에 여러 요청 지원을 추가했습니다. gist.github.com/1431613
Chad Scira 2011

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

사용 샘플 :

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

1
window[callback] = null함수가 가비지 수집되도록 허용하는 것을 잊지 마십시오 .
Sukima

3

가능한 한 간단하게이를 처리하기 위해 라이브러리를 작성했습니다. 외부로 만들 필요가 없으며 하나의 기능입니다. 다른 옵션과 달리이 스크립트는 자체적으로 정리되며 런타임시 추가 요청을 만들기 위해 일반화됩니다.

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없이 전화를 걸 JavaScript려면 아래 예제를 찾으십시오 JSONP.

또한 참조를 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);
    }
}


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

window.document.getElementsByTagName('script')[0];안돼 document.body.appendChild(…)?
Sukima

logAPI로 설정 null가비지 컬렉션은 그것을 수행 할 수 있도록 할 때?
Sukima

0

NPM과 함께 ES6를 사용하는 경우 노드 모듈 "fetch-jsonp"를 사용해 볼 수 있습니다. Fetch API 일반 XHR 호출로 JsonP 호출을 지원합니다.

전제 조건 : isomorphic-fetch스택에서 노드 모듈 을 사용해야합니다 .


0

ES6 버전의 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)
    })
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.