jQuery getJSON 在本地工作,但不能跨域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6849802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 21:28:04  来源:igfitidea点击:

jQuery getJSON works locally, but not cross domain

jqueryjsoncross-domainjsonpgetjson

提问by Dusty

I've searched FOREVER and can't come up with a definitive answer to my problem. So here it is. I have a JSON file (I went to jsonlint to validate and it says its good) that looks like this (some information modified):

我已经搜索了 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"
    }
]

I used jQuery to parse through and put on an html page using this function:

我使用 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');
});

It works perfectly! Now comes my issue, the JSON file will not be hosted locally, and will in fact be hosted on a separate domain. So I modified my code as follows (after some reading) hoping to get it working:

它完美地工作!现在是我的问题,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');
});

By adding the 'callback' line I stopped getting a "Failed to load resource" error. However, nothing is happening. It is like the function I added isn't even there. I tried to take all of it out and add a simple 'alert(data)', but that didn't even fire. What am I doing wrong? A big problem is that I am 100% limited to just HTML and JavaScript to work (not my choice). Thanks for any help!

通过添加“回调”行,我不再收到“无法加载资源”错误。然而,什么也没有发生。就像我添加的功能甚至不存在一样。我试图把它全部去掉并添加一个简单的“警报(数据)”,但这甚至没有触发。我究竟做错了什么?一个大问题是我 100% 仅限于 HTML 和 JavaScript 来工作(不是我的选择)。谢谢你的帮助!

EDITOk, I don't have ability for the other server to dynamically add anything to the json file. So I modified by hardcoding a function around the json (smaller sample):

编辑好的,我没有能力让其他服务器动态地向 json 文件添加任何内容。所以我通过围绕json(较小的样本)硬编码一个函数来修改:

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

Everything now works! Thanks for all the help!

现在一切正常!感谢所有的帮助!

回答by Brad Christie

You need to look in to JSONP.

您需要查看JSONP

Essentially, when you try to load JSON from another domain, it fails because there is a domain boundary you can not cross. To avoid this, you have to PADit (P in JSONP). Padding it is essentially wrapping it in a function call (where the function name resides on your client.) e.g. a "normal" JSON response (say, for example, getjson.php):

本质上,当您尝试从另一个域加载 JSON 时,它会失败,因为存在您无法跨越的域边界。为避免这种情况,您必须对其进行填充(JSONP 中的 P)。填充它本质上是将它包装在一个函数调用中(函数名称位于您的客户端上。)例如一个“正常”的 JSON 响应(例如,getjson.php):

{foo:'bar'}

JSON with a callback of parseJSONbecomes (Say, for example, getjson.php?callback=parseJSON):

JSON 回调为parseJSON(例如,getjson.php?callback=parseJSON):

parseJSON({foo:'bar'})

Notice how the value that was supplied in callbackbecomes the name of the function your JSON response is now wrapped in.

请注意回调中提供的值如何成为您的 JSON 响应现在包装在其中的函数的名称。

Then your client will want to pass it to parseJSON, a function that exists on your client (that you've defined). jQuery (and other libraries) try to take care of this for you by generating some "random" function and then sending the response back through your original callback (all this is done under the hood).

然后您的客户将希望将其传递给parseJSON,一个存在于您的客户(您已定义)上的函数。jQuery(和其他库)尝试通过生成一些“随机”函数然后通过原始回调发送回响应来为您解决这个问题(所有这些都是在后台完成的)。

If you have control over the server page generating the JSON, implement a callback method so you can supply how the JSON should be wrapped so you can then work with it on your end. (This is only necessary when you're dealing with data from a domain other than the page the client is currently on).

如果您可以控制生成 JSON 的服务器页面,请实现一个回调方法,以便您可以提供 JSON 的包装方式,以便您可以在最后使用它。(仅当您处理来自客户端当前所在页面以外的域中的数据时才需要这样做)。



UPDATE

更新

To basically solve the problem you're having, you need to find a way to get your JSON information in to a JSONP call. Without knowing what language your "page.json" is in, here's the pseudo-code logic that it should contain:

要从根本上解决您遇到的问题,您需要找到一种方法将您的 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

If you decide to hard-code the function name instead of allow it to be supplied in the url as "callback", then you need to remember it. For the next example, let's imagine we named it MyJSONPCallback

如果您决定对函数名称进行硬编码,而不是允许它在 url 中作为“回调”提供,那么您需要记住它。对于下一个示例,假设我们将其命名为MyJSONPCallback

Now, in your client code, you can go ahead of use:

现在,在您的客户端代码中,您可以继续使用:

$.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!
  }
});

回答by arpad

For those using MVC ActionResult to generate JSONP, ASP.NET MVC does not ship with JSONP support out of the box, but it is easy to add with:

对于那些使用 MVC ActionResult 生成 JSONP 的人,ASP.NET MVC 没有提供开箱即用的 JSONP 支持,但很容易添加:

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

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

回答by procrazium

Brad Christie's answer helped me quickly get my code working. I am creating a new entry here since it is little simpler than the other solutions.

Brad Christie 的回答帮助我快速使我的代码正常工作。我在这里创建一个新条目,因为它比其他解决方案简单一点。

Following is the code that I run from http://localhost:5000-

以下是我从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);
        });


        })();

From the location at http://localhost:3000/auget_from_server, I return the following JSON in response (this part is specific to meteor but it will work for non-meteor servers also) -

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+''}]));

This prints the following in the logs -

这会在日志中打印以下内容 -

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

回答by psr

Browsers don't let this work as a security measure. You could check out JSONP as a way to get around this, though it is a HUGE security risk since it relies on running javascript supplied by the domain you are getting the JSON text from.

浏览器不允许将其用作安全措施。您可以查看 JSONP 作为解决此问题的一种方法,尽管它存在巨大的安全风险,因为它依赖于运行由您从中获取 JSON 文本的域提供的 javascript。

回答by CenterOrbit

I have not looked deeply into this issue, but I believe your problem relates to the same-domain-policy... you might want to look into this though : http://james.padolsey.com/javascript/cross-domain-requests-with-jquery/

我没有深入研究这个问题,但我相信你的问题与同域策略有关......你可能想研究这个:http: //james.padolsey.com/javascript/cross-domain-请求与 jquery/

回答by David Hoerster

See this article -- you have to supply a valid javascript object wrapped in a function.

请参阅这篇文章——您必须提供一个包含在函数中的有效 javascript 对象。

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

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

You'd want to return something like:

你想返回类似的东西:

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

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

But your server-side method would need to know to return that, instead of just the JSON inside. All jQuery does is auto-generate a function name (the ?in the callbackparameter) and then eval the "function" that's returned from the server. The server creates the function call with the JSON contained inside.

但是您的服务器端方法需要知道返回那个,而不仅仅是里面的 JSON。所有jQuery不会是自动生成的函数名(?callback这是一个从服务器返回的参数),然后EVAL的“功能”。服务器使用其中包含的 JSON 创建函数调用。