JSONP 回调函数

3
我正在研究JSONP回调函数的概念。我阅读了一些相关文章,希望能够深入了解JSONP的概念。
因此,我将一个JSON文件上传到服务器 - json file 以下是我编写的js代码,用于检索数据。调用是从本地主机到abhishekprakash.com进行的。
var xhr;
var dataList;
xhr = new XMLHttpRequest();

xhr.open('GET', 'http://abhishekprakash.com/script/example.json?callback=func_callbk',  true);
xhr.send();

func_callback = function(data){
    alert(data.data.people[0].id);
}

xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
            console.log(dataList);
    }
};

这是我在控制台中得到的响应:

snap shot of console

回调函数被调用,但它不包含Json数据。我缺少什么?任何帮助都将受到赞赏。谢谢。

哪个回调函数被调用?是onreadystatechange还是func_callback?看起来你的响应是JSON,而不是JSONP,所以我无法看到func_callback如何被调用。 - user1106925
该服务没有返回正确的JSONP响应。它是否明确支持JSONP调用? - deceze
@deceze 由于调用是跨域的,所以应该使用JSONP。这是JSONP的标准,对吧? - Abhishek Prakash
2
要么设置CORS头,要么使用JSONP。维基百科上有一篇关于同源策略的好文章,你完全误解了JSON和JSONP之间的区别。JSON是"{"message":"hello world"}",而JSONP是callback({message:"hello world"})。可以通过xhr检索JSON,而应该通过添加一个脚本元素并将其src属性设置为jsonp来检索jsonp的URL。然后在您的代码中,您需要为回调提供一个函数。 - HMR
是的,我现在真的很困惑。 :( - Abhishek Prakash
显示剩余2条评论
2个回答

16

那个示例服务返回的是JSON数据,而不是JSONP。

JSONP的意义在于,由于同源策略(Same Origin Policy)的安全限制,来自域A的Javascript无法向域B的资源发出GET请求;换句话说,脚本不能跨域检索数据。

JSONP通过使域B明确合作进行跨域数据共享来解决这个问题。来自域A的脚本指定回调函数的名称,并将域B的URL嵌入文档中,就像包含常规外部Javascript文件一样。然后域B输出像这样的数据:

callbackFuncName({ data : foo, ... });

这意味着域B明确输出一个调用指定回调函数并带有数据的Javascript片段

因此,除非域B明确合作,否则您无法简单地从中获取JSONP响应。


1
+1. 噢,完全没有看到楼主说他们上传了一个 JSON 文件 =/ - Ja͢ck
那么,是不是我需要在存放JSON文件的域中进行一些调整,以使其与需要数据的域相互配合? - Abhishek Prakash
@user 是的。您需要一个服务器端脚本来返回指定回调函数包装的JSON数据。此外,请参阅Jack的答案,了解如何正确地从Javascript进行调用。 - deceze
+1 我喜欢你明确地说另一端也需要合作发送正确的数据。不仅是一个端口,而是两个端口都需要。 - haxpor

7
XHR受限于跨域规则;要使用JSONP,您需要添加一个脚本元素:
function func_callbk()
{
    console.log(arguments);
}

var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'http://abhishekprakash.com/script/example.json?callback=func_callbk';
var h = document.getElementsByTagName('script')[0];
h.parentNode.insertBefore(s, h);

正如Ian在评论中指出的那样,您的服务器应该做出类似于以下的响应:
func_callbk('hello world')

更新

如果您希望在不使用JSONP的情况下使其工作(例如,响应始终应该是JSON),则需要查看CORS,如此答案所述。


1
为了让提问者理解,响应应该像这样:func_callbk(JSON_OBJECT); - Ian
@Ja͢ck,你能更直接地添加脚本元素吗?我选择了Github API示例演示他们的jsonp并稍作修改(链接),它似乎可以工作。不需要修改DOM来添加脚本标记,对吧? - Kedar Mhaswade
如果脚本已经包含在文档中,则不需要。 - Ja͢ck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接