說到AJAX就會不可避免的面臨兩個問題,第一個是AJAX以何種格式來交換數據?第二個是跨域的需求如何解決?數據可以用自定義字符串或者用XML來描述,跨域可以通過服務器端代理來解決。最被推崇或者說首選的方案還是用JSON來傳數據,靠JSONP來跨域。JSON是一種數據交換格式,而JSONP是一種依靠開發人員的聰明才智創造出的一種非官方跨域數據交互協議。
JSON的格式:
JSON能夠以非常簡單的方式來描述數據結構,XML能做的它都能做。
1、JSON只有兩種數據類型描述符,大括號{}和方括號[],其余英文冒號:是映射符,英文逗號,是分隔符,英文雙引號""是定義符。
2、大括號{}用來描述一組“不同類型的無序鍵值對集合”(每個鍵值對可以理解為OOP的屬性描述),方括號[]用來描述一組“相同類型的有序數據集合”(可對應OOP的數組)。
3、上述兩種集合中若有多個子項,則通過英文逗號,進行分隔。
4、鍵值對以英文冒號:進行分隔,並且建議鍵名都加上英文雙引號”",以便於不同語言的解析。
5、JSON內部常用數據類型無非就是字符串、數字、布爾、日期、null 這么幾個,字符串必須用雙引號引起來,其余的都不用,日期類型比較特殊,這里就不展開講述了,只是建議如果客戶端沒有按日期排序功能需求的話,那么把日期時間直接作為字符串傳遞就好,可以省去很多麻煩。
JSON實例:
var person = { // 描述一個人
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
}
var personAge = person.Age; // 獲取這個人的信息
var members = [ // 描述幾個人
{
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
}, {
"Name": "John",
"Age": 20,
"Company": "Oracle",
"Engineer": false
}, {
"Name": "Henry",
"Age": 45,
"Company": "Microsoft",
"Engineer": false
}
]
var johnsCompany = members[1].Company; // 讀取其中John的公司名稱
var conference = { // 描述一次會議
"Conference": "Future Marketing",
"Date": "2012-6-1",
"Address": "Beijing",
"Members":
[
{
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
}, {
"Name": "John",
"Age": 20,
"Company": "Oracle",
"Engineer": false
}, {
"Name": "Henry",
"Age": 45,
"Company": "Microsoft",
"Engineer": false
}
]
}
var henryIsAnEngineer = conference.Members[2].Engineer; // 讀取參會者Henry是否工程師
JSONP是怎么產生的
1、一個眾所周知的問題,Ajax直接請求普通文件存在跨域無權限訪問的問題,甭管你是靜態頁面、動態網頁、web服務、WCF,只要是跨域請求,一律不准;
2、不過我們又發現,Web頁面上調用js文件時則不受是否跨域的影響(不僅如此,我們還發現凡是擁有”src”這個屬性的標簽都擁有跨域的能力,比如<script>、<img>、<iframe>);
3、於是可以判斷,當前階段如果想通過純web端(ActiveX控件、服務端代理、屬於未來的HTML5之Websocket等方式不算)跨域訪問數據就只有一種可能,那就是在遠程服務器上設法把數據裝進js格式的文件里,供客戶端調用和進一步處理;
4、恰巧我們已經知道有一種叫做JSON的純字符數據格式可以簡潔的描述復雜數據,更妙的是JSON還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數據;
5、這樣子解決方案就呼之欲出了,web客戶端通過與調用腳本一模一樣的方式,來調用跨域服務器上動態生成的js格式文件(一般以JSON為后綴),顯而易見,服務器之所以要動態生成JSON文件,目的就在於把客戶端需要的數據裝入進去。
6、客戶端在對JSON文件調用成功之后,也就獲得了自己所需的數據,剩下的就是按照自己需求進行處理和展現了,這種獲取遠程數據的方式看起來非常像AJAX,但其實並不一樣。
7、為了便於客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作JSONP,該協議的一個要點就是允許用戶傳遞一個callback參數給服務端,然后服務端返回數據時會將這個callback參數作為函數名來包裹住JSON數據,這樣客戶端就可以隨意定制自己的函數來自動處理返回數據了。
JSONP的客戶端具體實現:
jQuery也好,ExtJs也罷,又或者是其他支持jsonp的框架
跨域js文件中的代碼(當然指符合web腳本安全策略的),web頁面也是可以無條件執行的。
服務端返回http://flightQuery.com/jsonp/flightResult.aspx
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
jsonp.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查詢結果后的回調函數
var flightHandler = function(data){
alert('你查詢的航班結果是:票價 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 張。');
};
// 提供jsonp服務的url地址(不管是什么類型的地址,最終生成的返回值都是一段javascript代碼)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 創建script標簽,設置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標簽加入head,此時調用開始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>
jQuery如何實現jsonp調用
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript" src=jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",
//傳遞給請求處理程序或頁面的,用以獲得jsonp回調函數名的參數名(一般默認為:callback)
jsonpCallback:"flightHandler",
//自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名,也可以寫"?",jQuery會自動為你處理數據
success: function(json){
alert('您查詢到航班信息:票價: ' + json.price + ' 元,余票: ' + json.tickets + ' 張。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>
說明
1、ajax和jsonp這兩種技術在調用方式上“看起來”很像,目的也一樣,都是請求一個url,然后把服務器返回的數據進行處理,因此jquery和ext等框架都把jsonp作為ajax的一種形式進行了封裝;
2、但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加<script>標簽來調用服務器提供的js腳本。
3、所以說,其實ajax與jsonp的區別不在於是否跨域,ajax通過服務端代理一樣可以實現跨域,jsonp本身也不排斥同域的數據的獲取。
4、還有就是,jsonp是一種方式或者說非強制性協議,如同ajax一樣,它也不一定非要用json格式來傳遞數據,如果你願意,字符串都行,只不過這樣不利於用jsonp提供公開服務。
jquery在處理jsonp類型的ajax時已把jsonp歸入了ajax
angularJS中jsonp的使用
myUrl = "http://localhost:8090/api/testcallback=JSON_CALLBACK";
$http.jsonp(myUrl).success(
function(data){
alert(data);
}
);
1.angularJS中使用$http.jsonp函數
2.指定callback和回調函數名,函數名為JSON_CALLBACK時,會調用success回調函數,JSON_CALLBACK必須全為大寫。
3.也可以指定其它回調函數,但必須是定義在window下的全局函數。
4.url中必須加上callback
5.當callback為JSON_CALLBACK時,只會調用success,即使window中有JSON_CALLBACK函數,也不會調用該函數。
瀏覽器是存在同源策略這個機制的,在全局層面禁止了頁面加載或執行與自身來源不同的域的任何腳本。
JSONP是一種可以繞過瀏覽器的安全限制,從不同的域請求數據的方法。
Jquery中jsonp的使用
myUrl = "http://localhost:8090/api/test";
$.ajax({
type:"GET",
url:myUrl,
dataType:"jsonp",
jsonp:"callback",
jsonpCallback:"jsonpCallback",
success:function(data){
alert(data.msg);
}
});
function jsonpCallback(data){
alert(data);
}
1.jsonp只能使用get請求,解決同源問題,返回javascript代碼,因為請求javascript文件是沒有同源問題的。
2.當請求數據類型為jsonp時,會將callback=jsonpCallback加在url上,http://localhost:8090/api/testcallback=jsonpCallback
3.前台javascript中定義jsonpCallback函數,此函數必須定義在window下,也就是全局的函數,否則找不到。
4.后台獲取請求的callback參數值jsonpCallback,返回字符串"jsonpCallback(result)",result為返回結果。
5.請求返回的是script tag,首先會調用jsonpCallback函數,不管是否找到該函數,都會調用success函數。
6.如果沒有定義jsonp和jsonpCallback,jsonp默認為"callback",jsonpCallback會是Jquery自動生成的函數名。