JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。

由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com 的服务器沟通,而 HTML 的 <script> 元素是一个例外。利用 <script>元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的 JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。

原理

将原来返回script脚本的url,现在返回json数据,这样动态的来获取数据。然而,一份 JSON 文件并不是一个 JavaScript 程式。为了让浏览器可以在 <script> 元素执行,从 src 里 URL 回传的必须是可执行的 JavaScript。在 JSONP 的使用模式里,该 URL 回传的是由函数呼叫包起来的动态生成 JSON,这就是JSONP 的“填充(padding)”或是“前辍(prefix)”的由来。

例如:

1
2
3
<script type="text/javascript"
src="http://server2.example.com/RetrieveUser?UserId=1823&jsonp=parseResponse">
</script>

服务器返回的数据是:

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

流程是这样的:

如果点击按钮触发获取不同域的数据,在js里面操作动态添加一个<script>节点到dom当中,url来指向提供jsonp服务的地方。就使用上面的地址,返回的数据当中执行了parseResponse这个方法。所以我们需要在本地增加这个parseResponse方法来处理回调。如下:

1
2
3
4
function parseResponse(data) {
alert(data.Name);
alert(data.Id);
}

这样就完整的处理了一个jsonp的请求。

具体例子

要使用jsonp首先需要有提供jsonp服务的后端,这里面使用百度的查询jsonp服务。

例子分两种实现方式:js原生和jquery库提供。

  • js原生如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title></title>
<script src="js/jquery-2.0.3.min.js"></script>
<script>
function keyup(obj) {
var jsonp = document.createElement("script");
jsonp.id = "cb";
jsonp.src = "http://suggestion.baidu.com/su?wd=" +
$(obj).val() + "&json=1&p=3&req=2&cb=callback";
document.body.appendChild(jsonp);
}

function callback(data) {
var html = "<ul>";
for (var i = 0; i < data.s.length; i++) {
html = html + "<li>" + data.s[i] + "</li>";
}
html = html + "</ul>";
$("#div").html(html);
}
</script>
</head>

<body>
百度:
<input type="text" onkeyup="keyup(this)" />
<div id="div">
</div>
</body>

</html>
  • jquery如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/jquery-2.0.3.min.js"></script>
<script>
function keyUp(obj) {
jQuery.getJSON("http://suggestion.baidu.com/su?wd=" +
$(obj).val() + "&json=1&p=3&req=2cb=?", function(data) {
var html = "<ul>";
for(var i =0; i < data.s.length; i ++) {
html = html + "<li>" + data.s[i] + "</li>";
}
html = html + "</ul>";
$("#div").html(html);
});
}
</script>
</head>

<body>
百度:
<input type="text" onkeyup="keyUp(this)" />
<div id="div">
</div>
</body>

</html>

当然使用jquery的形式更加简单明了,并且如果请求的后端服务不是jsonp服务,jquery会当作普通的ajax进行处理。js原生处理的过程当中并没有很严谨的处理生成的<script>,如果调用的多次会产生很多的<script>,所以在每次请求的时候需要判断是否包含<script>如果包含的话还需要remove掉然后再append。

—EOF—