JQuery getJSON работает локально, но не перекрестный домен

Я искал FOREVER и не могу найти окончательного ответа на мою проблему. Так вот оно. У меня есть файл JSON (я пошел в jsonlint для проверки, и он говорит, что это хорошо), который выглядит так (некоторая информация изменена):

[{
        "position":"1",
        "category":"A",
        "title":"Title to first story",
        "description":"The first story."
    },
    {
        "position":"2",
        "category":"B",
        "title":"Title to second story",
        "description":"The second story"
    },
    {
        "position":"3",
        "category":"B",
        "title":"Title to third story",
        "description":"The third story"
    }
]

Я использовал jQuery для синтаксического анализа и размещения на html-странице с помощью этой функции:

$.getJSON('page.json', function(data) {
  var items = [];

  $.each(data.reponse, function(item, i) {
    items.push('<li id="' + i.position + '">' + i.title + ' - ' + i.description + '</li>');
  });

  $('<ul/>', {
    'class': 'my-new-list',
    html: items.join('')
  }).appendTo('body');
});

Он отлично работает! Теперь моя проблема: файл JSON не будет размещен локально и фактически будет размещен в отдельном домене. Поэтому я изменил свой код следующим образом (после некоторого чтения), надеясь заставить его работать:

$.getJSON('http://www.otherdomain.com/page.json?format=json&callback=?', function(data) {
  var items = [];

  $.each(data.reponse, function(item, i) {
    items.push('<li id="' + i.position + '">' + i.title + ' - ' + i.description + '</li>');
  });

  $('<ul/>', {
    'class': 'my-new-list',
    html: items.join('')
  }).appendTo('body');
});

Добавив строку "обратный вызов", я перестала получать ошибку "Ошибка загрузки ресурса". Однако ничего не происходит. Это похоже на функцию, которую я добавил, даже там нет. Я попытался взять все это и добавить простое "предупреждение (данные)", но это даже не срабатывало. Что я делаю не так? Большая проблема в том, что я на 100% ограничен только HTML и JavaScript для работы (не мой выбор). Спасибо за любую помощь!

ИЗМЕНИТЬ Хорошо, у меня нет возможности для другого сервера динамически добавлять что-либо в json файл. Поэтому я модифицировал путем жесткого кодирования функции вокруг json (меньшая выборка):

storyData(
[{
        "position":"1",
        "category":"A",
        "title":"Title to first story",
        "description":"The first story."
    }
])

Теперь все работает! Спасибо за помощь!

Ответ 1

Вам нужно посмотреть JSONP.

По сути, когда вы пытаетесь загрузить JSON из другого домена, он терпит неудачу, потому что есть граница домена, которую вы не можете пересечь. Чтобы этого избежать, вы должны PAD его (P в JSONP). Заполнение его по сути сводит его к вызову функции (где имя функции находится на вашем клиенте). "нормальный" ответ JSON (скажем, например, getjson.php):

{foo:'bar'}

JSON с обратным вызовом parseJSON становится (скажем, getjson.php? callback = parseJSON):

parseJSON({foo:'bar'})

Обратите внимание, как значение, которое было отправлено в обратном вызове, становится именем функции, в которой ваш ответ JSON теперь завернут.

Затем ваш клиент захочет передать его в parseJSON, функцию, существующую на вашем клиенте (которую вы определили). jQuery (и другие библиотеки) стараются позаботиться об этом для вас, генерируя некоторую "случайную" функцию, а затем отправляя ответ обратно через ваш оригинальный обратный вызов (все это делается под капотом).

Если у вас есть контроль над страницей сервера, создающей JSON, внедрите метод обратного вызова, чтобы вы могли указать, как JSON должен быть обернут, чтобы вы могли работать с ним на вашем конце. (Это необходимо только в том случае, если вы имеете дело с данными из домена, отличного от страницы, на которой в данный момент находится клиент).


UPDATE

Чтобы решить проблему, которую вы имеете, вам нужно найти способ получить информацию JSON для вызова JSONP. Не зная, на каком языке находится ваш "page.json", вот логика псевдокода, которую он должен содержать:

if GET_VARIABLE("callback") is supplied

  print GET_VARIABLE("callback") and an open parenthesis
  print normal JSON data
  print closing parenthesis

else

  print normal JSON data

end if

Если вы решите жестко закодировать имя функции вместо того, чтобы разрешить ее подавать в URL-адрес как "обратный вызов", вам необходимо запомнить его. В следующем примере предположим, что мы назвали его MyJSONPCallback

Теперь, в вашем клиентском коде, вы можете использовать:

$.ajax({
  url: 'http://anotherdomain.com/page.json?format=json',
  dataType: 'json',
  jsonpCallback: 'MyJSONPCallback', // specify the callback name if you're hard-coding it
  success: function(data){
    // we make a successful JSONP call!
  }
});

Ответ 2

Для тех, кто использует MVC ActionResult для генерации JSONP, ASP.NET MVC не поставляется с поддержкой JSONP из коробки, но его легко добавить с помощью

http://nikcodes.com/2012/02/29/an-asp-net-mvc-jsonp-actionresult

Ответ 3

Браузеры не позволяют этому работать как мера безопасности. Вы можете проверить JSONP как способ обойти это, хотя это ОГРОМНЫЙ риск для безопасности, поскольку он полагается на запуск javascript, предоставленный доменом, из которого вы получаете текст JSON.

Ответ 5

См. эту статью - вы должны указать действительный объект javascript, завернутый в функцию.

http://en.wikipedia.org/wiki/JSONP

Вы хотите вернуть что-то вроде:

parseResponse({"Name": "Cheeso", "Id" : 1823, "Rank": 7})

Но ваш серверный метод должен знать, чтобы вернуть это, а не только JSON внутри. Все jQuery выполняет автоматическое создание имени функции (? в параметре callback), а затем eval "функция", возвращаемая с сервера. Сервер создает вызов функции с включенным JSON.

Ответ 6

Ответ Брэда Кристи помог мне быстро заставить работать мой код. Я создаю новую запись здесь, так как она немного проще других решений.

Ниже приведен код, который я запускал из http://localhost:5000 -

(function() {
        var api = "http://www.localhost:3000/auget_from_server?format=json";
        var request = $.getJSON( api, {
            secret : 'secret', 
            appId : 'app', 
            emailId : '[email protected]',
            async: false,
            dataType : 'json',
          },
          function(data, result){
            $("div.some_div").append(JSON.stringify(data));
          });

        request.complete(function(d, status){
            console.log('Complete the request and got the data - ' + JSON.stringify(d) + '/' + status, filename);
        });

        request.error(function(err){
            console.log('Error happened - ', filename);
            console.log(err);
        });

        request.success(function( data, status, jqXHR ) {
            $("div.some_div").append(data);
        });


        })();

От местоположения http://localhost:3000/auget_from_server я возвращаю следующий JSON в ответ (эта часть специфична для метеорита, но она будет работать для не- -метеорные серверы) -

this.response.writeHead('200', {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*'});
this.response.end(JSON.stringify([{'works_or_not' : 'works', 'name' : 'akaushik', 'application' : 'Qoll', 'message' : 'hello from server', 'currentTime' : dt+''}]));

Это выводит следующие данные в журналах -

Complete the request and got the data - {"readyState":4,"responseText":"[{\"works_or_not\":\"works\",\"name\":\"akaushik\",\"application\":\"Qoll\",\"message\":\"hello from server\",\"currentTime\":\"Tue Dec 15 2015 23:59:14 GMT-0500 (EST)\"}]","responseJSON":[{"works_or_not":"works","name":"akaushik","application":"Qoll","message":"hello from server","currentTime":"Tue Dec 15 2015 23:59:14 GMT-0500 (EST)"}],"status":200,"statusText":"OK"}/success