1、Jsonp
Jsonp(json with padding)是JSON的一種“使用模式”,可用於解決主流瀏覽器的跨域數據訪問的問題。
Jsonp是為了解決ajax跨域發送http請求出現的,利用Script標簽的特性跨域。瀏覽器由於安全考慮,在編寫ajax程序時,httprequest/xmlhttp都不能發送非本域的http請求,是被瀏覽器所禁止的。所以ajax本身是無法跨域的。
2、同源策略
www.a.com網頁的ajax獲取www.b.com接口的內容,由於您的網頁域名是www.a.com,而您發送的ajax請求的目標域卻是www.b.com。瀏覽器會阻止這一的請求,這就是所謂的同源策略。
同源是指:js腳本只能訪問或者請求相同協議,相同domain(網址/ip),相同端口的頁面。
我們知道,js腳本可以訪問所在頁面的所有元素。通過ajax技術,js也可以訪問同一協議,同一個domain(ip),同一端口的服務器上的其他頁面,請求到瀏覽器端之后,利用js就可以進行任意的訪問。但是對於協議不同, 或者domain不同或者端口不同的服務器上的頁面就無能為力了,完全不能進行請求。下面是例子:(http://localhost:57269/頁面)
varxmlhttp;if(window.XMLHttpRequest) {
xmlhttp= newXMLHttpRequest();
}else{
xmlhttp=ActionXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange= function() {if(xmlhttp.readyState== 4 &&xmlhttp.status== 200) {
console.log(xmlhttp.responseText);
}
}varurl= "http://localhost:51355/Common/Test";
xmlhttp.open("Get", url,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send();
這里為了結果不受其他js庫的干擾,使用了原生的XMLHttpRequest來處理,結果如下:
我們看到57269端口的ajax請求無法訪問51355端口的頁面。原因是“同源策略禁止讀取“某某”的遠程資源”。因為同源策略,普通的ajax無法跨域請求,解決這種問題的方式就是Jsonp。
3、Jsonp跨域的原理
我們發現凡是擁有"src"這個屬性的標簽都擁有跨域的能力,在頁面上有三種資源是可以與頁面本身不同源的。它們是:js腳本,css樣式文件,圖片,如下所示,它們是可以鏈接訪問到不同源的資源的。
1)
2)
3)
而jsonp就是利用了標簽可以鏈接到不同源的js腳本,來到達跨域目的。當鏈接的資源到達瀏覽器時,瀏覽器會根據他們的類型來采取不同的處理方式,比如,如果是css文件,則會進行對頁面 repaint,如果是img 則會將圖片渲染出來,如果是script 腳本,則會進行執行,比如我們在頁面引入了jquery庫,為什么就可以使用 $了呢?就是因為jquery庫被瀏覽器執行之后,會給全局對象window增加一個屬性:$,所以我們才能使用 $來進行各種處理。(另外為什么要一般要加css放在頭部,而js腳本放在body尾部呢,就是為了減少repaint的次數,另外因為js引擎是單線程執行,如果將js腳本放在頭部,那么在js引擎在執行js代碼時,會造成頁面暫停。)
jQuery封裝的 josnp 用法:
//第一種方式getJSON callback=?,其中 ? 會自動替換為function(data)函數。
$.getJSON("http://localhost:51355/Common/Test?callback=?", function(data) {var obj = JSON.parse(data); //很多網上的例子都是可以直接.age這樣寫的,但是我測試的時候無法這么做,必須要轉一次josn,需要轉josn,未能清楚為何沒有自動為我轉成json格式。
alert(obj.age);
});//第二種方式ajax,設定請求方式為jsonp
$.ajax({
async:false,
url:"http://localhost:51355/Common/Test", //跨域的url
type: "GET",
dataType:'jsonp', //返回格式
jsonp: "callback", //指定回調函數
data: "", //參數
success: function(data) {var obj = JSON.parse(data); //很多網上的例子都是可以直接.age這樣寫的,但是我測試的時候無法這么做,必須要轉一次josn,需要轉josn,未能清楚為何沒有自動為我轉成json格式。
alert(obj.age);
}
});
//需要考證是否正確
//jsonp: "callback", // 指定回調函數,這里名字可以為其他任意你喜歡的,比如callback,不過必須與下一行的GET參數一致
//data: "name=jxq&email=feichexia@yahoo.com.cn&callback=?", // callback與上面的jsonp值一致
C# MVC代碼:
//方式一
publicActionResult Test()
{string callback = Request["callback"]; //jsonp1503629838983
string name = "mr.zhang";string age = "20";string response = "{\"name\":\"" + name + "\",\"age\":\"" + age + "\"}";
System.Web.Script.Serialization.JavaScriptSerializer jss= newSystem.Web.Script.Serialization.JavaScriptSerializer();string call = callback + "(" + jss.Serialize(response) + ")"; //jsonp1503629838983("{\"name\":\"mr.zhang\",\"age\":\"20\"}")
returnContent(call);
}//方式二
public voidTest()
{string callback = Request["callback"]; //jsonp1503629838983
string name = "mr.zhang";string age = "20";string response = "{\"name\":\"" + name + "\",\"age\":\"" + age + "\"}";
System.Web.Script.Serialization.JavaScriptSerializer jss= newSystem.Web.Script.Serialization.JavaScriptSerializer();string call = callback + "(" + jss.Serialize(response) + ")"; //jsonp1503629838983("{\"name\":\"mr.zhang\",\"age\":\"20\"}")
Response.Write(call);
Response.End();
}
下面是我理解的josnp的原理(個人觀點):
一個簡單的JSONP請求可以通過一下代碼實現:
var callbackName = 'callback';
window[callbackName]= function(data) {var obj = JSON.parse(data); //很多網上的例子都是可以直接.age這樣寫的,但是我測試的時候無法這么做,必須要轉一次josn,需要轉josn,未能清楚為何沒有自動為我轉成json格式。
alert(obj.age);
}var script = document.createElement('script');
script.src= 'http://localhost:51355/Common/Test?callback=' +callbackName;
document.body.appendChild(script);
大概可以看出來,是創建了一個標簽,然后把我想請求的地址賦值給src。這樣我是不是可以繼續精簡一下。
Html的head代碼:
functioncallback(data) {varobj=JSON.parse(data);//轉josnalert(obj.age);
}
4、總結
1、這是我認為的josnp代碼實現方式,應該是先創建了一個類似callback函數,然后創建一個的標簽,通過標簽中的src指定的js腳本到達瀏覽器會執行的特性,發起請求告訴服務端函數名叫callback。html會把返回的字符串當作javascript代碼來進行解析,然后返回的是一個函數包裹的josn數據callback(josn),即callback("{\"name\":\"mr.zhang\",\"age\":\"20\"}"),然后調動本地的callback函數輸出josn。
2、jQuery是將jsonp封裝成類似ajax的樣子,是自動生成回調函數並把數據取出來供success屬性方法來調用。
3、因為標簽的請求方式就是Get。所以Jsonp只能使用Get請求,即使jQuery方式的ajax里寫的是post方式,最后也是get方式請求。