

參數jsonp 和 jsonpCallback
jsonp指定使用哪個名字將回調函數傳給服務端,也就是在服務端通過 request.getParameter(""); 的那個名字,而jsonpCallback就是request.getParamete("")取得的值,也就是回調函數的名稱。其實這兩個參數都可以不指定,只要我們是通過 success : 來指定回調函數的情況下,就可以省略這兩個參數,jsnop如果不知道,默認是 "callback",jsnpCallback不指定,是jquery自動生成的一個函數名稱,其對應源碼如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
var
oldCallbacks = [],
rjsonp = /(=)\?(?=&|$)|\?\?/;
// Default jsonp settings
jQuery.ajaxSetup({
jsonp:
"callback"
,
jsonpCallback:
function
() {
var
callback = oldCallbacks.pop() || ( jQuery.expando +
"_"
+ ( nonce++ ) );
this
[ callback ] =
true
;
return
callback;
}
});
|
(1)訪問js
8888端口的html4項目中的jsonp.html頁面代碼如下:
|
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
|
<!
doctype
html>
<
html
>
<
head
>
<
meta
charset="utf-8">
<
meta
name="keywords" content="jsonp">
<
meta
name="description" content="jsonp">
<
title
>jsonp</
title
>
</
head
>
<
body
>
<
script
type="text/javascript" src="js/jquery-1.11.1.js"></
script
>
<
script
type="text/javascript">
var url = "http://localhost:8080/html5/jsonp_data.js";
// 創建script標簽,設置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標簽加入head,此時調用開始
document.getElementsByTagName('head')[0].appendChild(script);
function callbackFun(data)
{
console.log(data.age);
console.log(data.name);
}
</
script
>
</
body
>
</
html
>
|
其訪問的8080端口的html5項目中的jsonp_data.js代碼如下:
|
1
|
callbackFun({
"age"
:100,
"name"
:
"yuanfang"
})
|
將兩個tomcate啟動,用瀏覽器訪問8888端口的html4項目中的jsonp.html,結果如下:

上面我們看到,我們從8888 端口的頁面通過 script 標簽成功 的訪問到了8080 端口下的jsonp_data.js中的數據。這就是 jsonp 的基本原理,利用script標簽的特性,將數據使用json格式用一個函數包裹起來,然后在進行訪問的頁面中定義一個相同函數名的函數,因為 script 標簽src引用的js腳本到達瀏覽器時會執行,而我們有定義了一個同名的函數,所以json格式的數據,就做完參數傳遞給了我們定義的同名函數了。這樣就完成了跨域數據交換。jsonp的含義是:json with padding,而在json數據外包裹它的那個函數,就是所謂的 padding 啦^--^
(2)訪問servlet---比較實用的例子
8080端口的html5項目中定義一個servlet:
package com.tz.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
@WebServlet("/JsonServlet")
public class JsonServlet extends HttpServlet
{
private static final long serialVersionUID = 4335775212856826743L;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String callbackfun = request.getParameter("mycallback");
System.out.println(callbackfun); // callbackFun
response.setContentType("text/json;charset=utf-8");
User user = new User();
user.setName("yuanfang");
user.setAge(100);
Object obj = JSON.toJSON(user);
System.out.println(user); // com.tz.servlet.User@164ff87
System.out.println(obj); // {"age":100,"name":"yuanfang"}
callbackfun += "(" + obj + ")";
System.out.println(callbackfun); // callbackFun({"age":100,"name":"yuanfang"})
response.getWriter().println(callbackfun);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
this.doPost(request, response);
}
}
在8888端口的html4項目中的jsonp.html來如下的跨域訪問他:
|
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
36
37
38
39
40
41
42
43
44
|
<!
doctype
html>
<
html
>
<
head
>
<
meta
charset="utf-8">
<
meta
name="keywords" content="jsonp">
<
meta
name="description" content="jsonp">
<
title
>jsonp</
title
>
<
style
type="text/css">
*{margin:0;padding:0;}
div{width:600px;height:100px;margin:20px auto;}
</
style
>
</
head
>
<
body
>
<
div
>
<
a
href="javascript:;">jsonp測試</
a
>
</
div
>
<
script
type="text/javascript" src="js/jquery-1.11.1.js"></
script
>
<
script
type="text/javascript">
function callbackFun(data)
{
console.log(111);
console.log(data.name);
//data.age = 10000000;
//alert(0000);
}
$(function(){
$("a").on("click", function(){
$.ajax({
type:"post",
url:"http://localhost:8080/html5/JsonServlet",
dataType:'jsonp',
jsonp:'mycallback',
jsonpCallback:'callbackFun',
success:function(data) {
console.log(2222);
console.log(data.age);
}
});
})
});
</
script
>
</
body
>
</
html
>
|
結果如下:

我們看到,我們成功的跨域取到了servlet中的數據,而且在我們指定的回調函數jsonpCallback:'callbackFun' 和 sucess 指定的回調函數中都進行了執行。而且總是callbackFun先執行,如果我們打開注釋://data.age = 10000000; //alert(0000);
就會發現:在callbackFun中對 data 進行修改之后,success指定的回調函數的結果也會發生變化,而且通過alert(0000),我們確定了如果alert(000)沒有執行完,success指定的函數就不會開始執行,就是說兩個回調函數是先后同步執行的。
注:雖然ajax封裝了jsop跨域請求但是不支持async:false,依然是同步的,因為ajax本質是xmlhttprequest請求,jsonp是js語法。
結果如下:

從上面的介紹和例子,我們知道了 jsonp 跨域的原理,是利用了script標簽的特性來進行的,但是這和ajax有什么關系呢?顯然script標簽加載js腳本和ajax一點關系都沒有,在沒有ajax技術之前,script標簽就存在了的。只不過是jquery的封裝,使用了ajax來向服務器傳遞 jsonp 和 jsonpCallback 這兩個參數而已。如果我們再服務器端和客戶端,對參數 jsonp 和 jsonpCallback 的值,協調好(也就是一致性),那么就沒有必要使用ajax來傳遞着兩個參數了,就像上面第二個例子那樣,直接構造一個script標簽就行了。不過實際上,我們還是會使用ajax的封裝,因為它在調用完成之后,又將動態添加的script標簽去掉了

