前言
ajax,用蒼白的話讚揚:很好。
我們可以使用ajax實現非同步擷取資料,減少伺服器運算時間,大大地改善使用者體驗;我們可以使用ajax實現小系統組合大系統;我們還可以使用ajax實現前端的最佳化。(好一個排比)
雖然ajax很好,但在使用起來也會有一定的限制,出於安全考慮,不允許跨域通訊。如果嘗試從不同的域請求資料,會出現安全錯誤。(下面例子1可以直觀看出)
同源策略限制
同源策略阻止從一個域上載入的指令碼擷取或操作另一個域上的文件屬性。也就是說,受到請求的 URL 的域必須與當前 Web 頁面的域相同。這意味著瀏覽器隔離來自不同源的內容,以防止它們之間的操作。這個瀏覽器策略很舊,從 Netscape Navigator 2.0 版本開始就存在。——摘自developerWorks
所謂同源是指,網域名稱,協議,連接埠相同。
平地一聲吼
本文講解的是怎麼利用ajax實現跨域請求,那麼知道“同源策略”,就可以解決很多疑問:“為毛我的ajax載入不了資料!”“為毛瀏覽器控制台會對我如此漂亮的代碼報錯!”
例子1
先上一個錯誤示範
用戶端代碼:
複製代碼 代碼如下:
<script>
// 用戶端使用getJSON方法請求另一台機子上的指令碼
$.getJSON("http://172.22.22.120/new/ajax.php",function(json){
alert(json.website);
});
</script>
服務端PHP指令碼代碼:
複製代碼 代碼如下:
<?php
// ajax.php
header('Content-type: application/json');
echo json_encode(array('website'=>'hcoding'));
?>
firefox下的錯誤提示:
根據同源策略的概念,localhost和172.22.22.120是出於不同的網域名稱下的,所以跨域請求理所當然地被瀏覽器拒絕了。
JSONP
JSONP(JSON with Padding)是資料格式 JSON 的一種“使用模式”,可以讓網頁從別的網域要資料。另一個解決這個問題的新方法是跨來源資源共用。由於同源策略,一般來說位於 server1.example.com 的網頁無法與不是 server1.example.com 的伺服器溝通,而 HTML 的 <script> 元素是一個例外。利用 <script> 元素的這個開放策略,網頁可以得到從其他來源動態產生的 JSON 資料,而這種使用模式就是所謂的 JSONP。用 JSONP 抓到的資料並不是 JSON,而是任意的 JavaScript,用 JavaScript 直譯器執行而不是用 JSON 解析器解析。——摘自維基百科
這話該怎麼理解呢!我個人是這樣認為的,用<script>跨域的請求資料,跨域的伺服器返回一段【JavaScript代碼】,是 的,你沒看錯,不是json格式資料,是JavaScript代碼,這樣,這段代碼就由JavaScript 直譯器執行。上例子更直觀:
例子2
用戶端代碼:
複製代碼 代碼如下:
<script>
// 這是回調方法
function cb(data){
alert(data.website);
}
</script>
<!--這是跨域請求的代碼,切記,這段代碼要在回呼函數之後-->
<script src="http://172.22.22.120/new/ajax_jsonp.php?callback=cb"></script>
服務端PHP指令碼代碼:
複製代碼 代碼如下:
<?php
$cb = htmlspecialchars($_GET['callback']); // 注意了,這裡要做好過濾,防止xss攻擊
echo $cb,'(',json_encode(array('website'=>'hcoding')),')'; // 返回用戶端的資料為:cb({"name":"hcoding"}) 這是一段js代碼
?>
瀏覽器會發生什麼事呢,我就不說了,當然是cb方法被調用啦:
所以,再說jsonp的概念,利用<script>不受同源策略的限制,跨域的伺服器把要返回的json資料作為參數和回呼函數一起返回用戶端。
JQuery對JSONP的支援
本文要講ajax的跨域請求,前面說了那麼多,下面當然要講主題啦。
從 1.2 版本開始,jQuery 擁有對 JSONP 回調的本地支援。如果指定了 JSONP 回調,就可以載入位於另一個域的 JSON 資料,回調的文法為:url?callback=?。jQuery 自動將 ? 替換為要調用的產生函數名。
例子3:$.getJSON方法跨域請求
例子4:$.ajax方法自訂回調方法
例子3
用戶端代碼:
複製代碼 代碼如下:
<script>
// 用戶端使用getJSON方法請求另一台機子上的指令碼
// 瀏覽器會產生一個隨機的callback參數
$.getJSON("http://172.22.22.120/new/ajax_jsonp.php?callback=?",function(json){
alert(json.website);
});
</script>
服務端PHP指令碼代碼:
複製代碼 代碼如下:
<?php
$cb = htmlspecialchars($_GET['callback']); // 注意了,這裡要做好過濾,防止xss攻擊
echo $cb,'(',json_encode(array('website'=>'hcoding')),')'; // 返回用戶端的資料,這是一段js代碼
?>
$.getJSON簡單易用,但就是不能指定回呼函數。
例子4
用戶端代碼:
複製代碼 代碼如下:
<script>
$.ajax({
type : "GET",
url : "http://172.22.22.120/new/ajax_jsonp.php",
dataType : "jsonp", // 資料格式指定為jsonp
jsonp: "callback", // 服務點通過這個索引值擷取回調方法
jsonpCallback:"cb", // 指定回調方法
success : function(json){
},
});
// 回調方法
function cb(data){
alert(data.website);
}
</script>
服務端PHP指令碼代碼和例子3的相同。
總結
正所謂無規矩不成方圓,以安全為出發點,遵循同源策略是一個好品德。但我們也有跨域請求的需求,jsonp就能滿足我們的需求。當然跨域請求還有很多的方法,不單止jsonp。
以上所述就是本文的全部內容了,希望大家能夠喜歡。