Как сделать запрос JSONP из Javascript без JQuery? - PullRequest
117 голосов
/ 26 мая 2011

Можно ли сделать междоменный запрос JSONP в JavaScript без использования jQuery или другой внешней библиотеки?Я хотел бы использовать сам JavaScript, а затем проанализировать данные и сделать его объектом, чтобы я мог его использовать.Должен ли я использовать внешнюю библиотеку?Если нет, то как я могу это сделать?

Ответы [ 12 ]

148 голосов
/ 26 мая 2011
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
36 голосов
/ 24 октября 2012

Легкий пример (с поддержкой 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

26 голосов
/ 01 февраля 2015

Что такое JSONP?

Важная вещь, которую следует помнить с помощью jsonp, это то, что на самом деле это не протокол или тип данных. Это просто способ загрузить скрипт на лету и обработать скрипт, который представлен на странице. В духе JSONP это означает введение нового объекта javascript с сервера в клиентское приложение / скрипт.

Когда нужен JSONP?

Это 1 метод, позволяющий одному домену асинхронно получать доступ / обрабатывать данные из другого на той же странице. Прежде всего, он используется для отмены ограничений CORS (Cross Origin Resource Sharing), которые могут возникнуть при запросе XHR (ajax). На загрузку скрипта не распространяются ограничения CORS.

Как это делается

Представление нового объекта javascript с сервера может быть реализовано многими способами, но наиболее распространенной практикой является выполнение сервером функции обратного вызова с передачей в нее необходимого объекта. Функция обратного вызова - это просто функция, которую вы уже настроили на клиенте, которую сценарий загружает вызовы в точке сценарий загружает для обработки переданных ему данных.

Пример:

У меня есть приложение, которое регистрирует все предметы в чьем-то доме. Мое приложение настроено, и теперь я хочу получить все предметы в главной спальне.

Мое приложение на app.home.com. API, с которого мне нужно загрузить данные, находятся на api.home.com.

Если сервер явно не настроен для его разрешения, я не могу использовать ajax для загрузки этих данных, поскольку даже страницы в отдельных поддоменах подчиняются ограничениям XHR CORS.

В идеале настройте параметры так, чтобы разрешить X-домен XHR

В идеале, поскольку API и приложение находятся в одном домене, у меня может быть доступ для настройки заголовков на api.home.com. Если я это сделаю, я могу добавить элемент заголовка Access-Control-Allow-Origin:, предоставляющий доступ к app.home.com. Предполагая, что заголовок настроен следующим образом: Access-Control-Allow-Origin: "http://app.home.com", это гораздо более безопасно, чем настройка JSONP. Это потому, что app.home.com может получить все, что ему нужно, от api.home.com без api.home.com, предоставляя CORS доступ ко всему интернету.

Указанное выше решение 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() как записано / echo / распечатано сервером. Данные, переданные в качестве параметра функции, теперь сохраняются в локальной переменной dataFromServer, и вы можете делать с ней все, что вам нужно.

Очистить

Как только у клиента есть данные, т.е. сразу после добавления сценария в DOM элемент сценария можно удалить из DOM:

script.parentNode.removeChild(script);
17 голосов
/ 26 мая 2011

Насколько я понимаю, вы на самом деле используете теги сценария с 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);

Сценарий загрузит JavaScript, созданный поставщиком API, и выполнит его.

8 голосов
/ 22 июля 2015

как я использую 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);
});

ссылка:

JavaScriptXMLHttpRequest с использованием JsonP

http://www.w3ctech.com/topic/721 (поговорим о способе использования Promise)

6 голосов
/ 27 мая 2011

У меня есть чистая библиотека JavaScript, чтобы сделать это https://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js

Посмотрите на это и дайте мне знать, если вам нужна помощь в использовании или понимании кода.

Кстати, у вас есть простой пример использования здесь: http://robertodecurnex.github.com/J50Npi/

5 голосов
/ 29 июня 2015
/**
 * 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');
2 голосов
/ 13 марта 2016

Я написал библиотеку, чтобы справиться с этим как можно проще.Не нужно делать его внешним, это всего лишь одна функция.В отличие от некоторых других опций, этот скрипт очищается после себя и обобщен для выполнения дальнейших запросов во время выполнения.

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);
                };
        });
}
1 голос
/ 29 мая 2018

Ниже приведен пример JavaScript, чтобы сделать JSONP звонок без JQuery:

Также вы можете сослаться на мой 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 голосов
/ 28 июня 2019

Просто вставьте версию ES6 в хороший ответ Собстеля:

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