JSONP请求的工作原理让你感到困惑了吗?

27

我对jsonp请求的细节理解有困难。我已经阅读了多个来源,包括jsonp的wiki页面,但仍然非常困惑回调函数如何获得从服务器返回的函数。例如,在wiki中,请求的源设置为:

src="http://server2.example.com/RetrieveUser?UserId=1234&jsonp=parseResponse"

jsonp = parseResponse到底是什么意思?然后他们接着说有效载荷是:

parseResponse({"Name": "Foo", "Id" : 1234, "Rank": 7});

这个是如何工作的?我对整个回调功能感到困惑。函数名parseResponse被传递到服务器,然后一些返回的数据会成为这个函数的参数?能否有人清楚地解释一下从jsonp请求中检索/使用数据的确切过程?


可能是请解释JSONP的重复问题。 - Jon
3个回答

51

回调函数是由你自己在代码中定义的函数。jsonp服务器将其响应封装在一个以你指定的回调函数同名的函数调用中。

具体来说,发生了以下情况:

1)你的代码创建JSONP请求,导致生成一个新的 <script> 块,它看起来像这样:

<script src="http://server2.example.com/RetrieveUser?UserId=1234&jsonp=parseResponse"></script>

2)那个新的脚本标签会被你的浏览器执行,导致向JSONP服务器发送请求。服务器会回复:

parseResponse({"Name": "Foo", "Id" : 1234, "Rank": 7});

3) 由于此请求来自脚本标签,因此它几乎与您实际放置的完全相同。

<script>
    parseResponse({"Name": "Foo", "Id" : 1234, "Rank": 7});
</script>

插入到你的页面中。

4) 现在远程服务器上的脚本已经被加载,它将会被执行,它唯一要做的就是调用一个函数parseResponse(),并将JSON数据作为函数调用的唯一参数。

因此,在代码的其他地方,你需要:

function parseResponse(data) {
     alert(data.Name); // outputs 'Foo'
}

基本上,JSONP 是绕过浏览器的同源策略的一种方式,通过让第三方服务器直接向您的页面注入函数调用来实现。需要注意的是,这种方法具有很高的不安全性,您要依靠远程服务是可信的且没有恶意意图。没有任何限制可以阻止不良服务返回一些 JavaScript 代码来窃取您的银行/ Facebook/ 或其他网站的凭据。例如... JSONP 响应可能是:

 internalUseOnlyFunction('deleteHarddrive');

你最好不要使用parseResponse(...),如果远程网站知道你代码的结构,它可以对该代码执行任意操作,因为你已经敞开大门让该网站想干什么就干什么。


8
我不会举deleteHardDrive这样的例子(JavaScript无法从浏览器执行该操作),但值得注意的是这可能很危险。 - hitautodestruct

1

编辑:正如Jon所说,这里有一个更好的解释here

JSONP使用脚本标签进行跨域请求。由于脚本标签用于包含脚本,因此服务器需要返回有效的JavaScript。我们通过函数调用将JavaScript传递给客户端。您告诉服务器要调用哪个函数来执行脚本,然后在本地创建该函数。当脚本加载完成时,您的函数将被调用,并将数据作为参数传递。

因此,如果您在提到的URL上进行了JSONP请求,并返回了您提到的有效载荷,您可以通过以下方式获取数据:

function parseResponse(data) {
    console.log("JSONP request complete", data);
}

返回的数据如何神奇地成为parseResponse函数的参数? - John Baum
@JohnBaum 是因为服务器创建了将被调用的 JS 代码吗? - Alex Turpin

0
函数名parseResponse被传递到服务器,一些数据返回后成为该函数的参数。
看起来你已经自己解释了,jsonp=parseResponse是这个应用程序设置回调函数的方式,因此它返回一个包含您的JSON数据的函数,看起来像这样。
parseResponse({"Name": "Foo", "Id" : 1234, "Rank": 7});

当它被加载时,会被称为,并由您的JS中的函数处理,例如:

function parseResponse(data){
    console.log(data);
}

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