使用jQuery與JSONP解決跨域問題

跨域問題存在實際上源於瀏覽器的同源策略(same origin policy),簡單講,同源就是要求域名,協議,端口三者都一致;而同源策略就是指頁面上的腳本不能訪問非同源的資源(包括HTTP響應和Cookie);
很多人會想到一個很熟悉的東西:document.domain
同源策略有點放鬆的就是:b.a.com上的頁面無法通過a.com的同源驗證,但是設置b.a.com頁面的document.domain 屬性爲a.com,就可以通過瀏覽器對a.com的同源檢測;但是,document.domain只允許設置成更上級的域名,而不是 其它域名,例如c.com就不行; 提到這裏很多人都會想到多級域 名下共享Cookie的路子就是把Cooki設置成上級域名;在Web2.0的時代,這種本質上同域跨級解決方案遠遠不能滿足我們跨域的需求;
我們要討論的是瀏覽器端的真正跨域訪問,推薦的是目前jQuery中$.ajax()支持get方式的跨域,這其實是採用jsonp的方式來完成的.
先來看jQuery的API中關於$.getJSON()的一個代碼示例:
1<script>
3    $.each(data.items, function(i,item){
4        $("<img/>").attr("src", item.media.m).appendTo("#p_w_picpaths");
5        if ( i == 3 ) return false;
6    });
7});
8</script>
這種方式其實是$.ajax({..}) api的一種高級封裝,有些$.ajax api底層的參數就被封裝而不可見了.
針對於上述代碼的請求,在服務器端通過 jsoncallback = $_GET["jsoncallback"] 得到jquery端隨後要回調的javascript函數名:jsonp1236827957501。
然後 response的內容爲一個腳本標籤:"jsonp1236827957501("+按請求參數生成的json數組+")";
jquery就會通過回調方法動態加載調用這個js tag:jsonp1236827957501(json數組);
這樣就達到了跨域數據交換的目的.
jsonp的最基本的原理是:動態添加一個script標籤,而script標籤的src屬性是沒有跨域的限制的。這樣說來,這種跨域方式其實與ajax XmlHttpRequest協議無關了.
這樣其實"jQuery AJAX跨域問題"就成了個僞命題了,jquery $.ajax方法名有誤導人之嫌.
如果設爲dataType: 'jsonp', 這個$.ajax方法就和ajax XmlHttpRequest沒什麼關係了,取而代之的則是JSONP協議.
JSONP是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過javascript callback的形式實現跨域訪問
JSONP即JSON with Padding。由於同源策略的限制,XmlHttpRequest只允許請求當前源(域名、協議、端口)的資源。如果要進行跨域請求,
我們可以通過使用html的script標記來進行跨域請求,並在響應中返回要執行的script代碼,其中可以直接使用JSON傳遞javascript對象。
這種跨域的通訊方式稱爲JSONP。
jsonCallback 函數jsonp1236827957501(....): 是瀏覽器客戶端註冊的,獲取跨域服務器上的json數據後,需要執行的回調函數。
Jsonp原理:
1,首先在客戶端註冊一個 callback (如:'jsoncallback'), 然後把callback的名字(如:jsonp1236827957501)傳給服務器。注意:服務端得到callback的數值後,要用 jsonp1236827957501(......)把將要輸出的json內容包括起來,此時,服務器生成 json 數據才能被客戶端正確接收。
2,然後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 'jsoncallback'的值 jsonp1236827957501 .
3,最後將 json 數據直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文檔,返回給客戶端。
4,客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文檔,此時javascript文檔數據,作爲參數,
傳入到了客戶端預先定義好的 callback 函數(如上例中jquery $.ajax()方法封裝的的success: function (json))裏.(動態執行回調函數)
可以說jsonp的方式原理上和“ ”是一致的(QQ空間以及ucenter的通信機制就是大量採用這種方式來實現跨域數據交換的) .JSONP是一種腳本注入(Script Injection)行爲,所以也有一定的安全隱患.
注意,jquey是不支持post方式跨域的.
爲什麼呢?
雖然採用post +動態生成iframe是可以達到post跨域的目的,但這樣做是一個比較極端的方式,不建議採用.
也可以說get方式的跨域是合法的,post方式從安全角度上,被認爲是不合法的, 萬不得已還是不要劍走偏鋒..
client端跨域訪問的需求看來也引起w3c的注意了,看資料說html5 WebSocket標準支持跨域的數據交換,應該也是一個將來可選的跨域數據交換的解決方案,
下面附上Cmstop中的跨域案例,供大家參考。
前臺頁面發出AJAX請求,獲取一篇文章的統計信息:
1var contentid = 123;
2$(function(){
3            $.getJSON(
4                        'http://app.cmstop.dev/?app=system&controller=content&action=stat&jsoncallback=?&contentid='+contentid,
5                        function(data){
6                                   if(data){
7                                               $('#pv').html(data.pv);
8                                   }
9                        }
10            );
11});
前臺應用接收請求並返回需要的數據:
1function stat()
2{
3$contentid = intval($_GET['contentid']);
4 
5$pv = loader::model('pv');
6$data['pv'] = $pv-&gt;get($contentid);
7 
8$comments = loader::model('comments');
9$data['comments'] = $comments-&gt;get($contentid);
10 
11$data['islogin'] = setting('comment', 'islogin') ? 1 : 0;
12 
13$data = $this-&gt;json-&gt;encode($data);
14echo $_GET['jsoncallback']."($data);";
15}
到這裏,我們關於使用jQuery與JSONP解決跨域問題已經可以解決了。當我們以後在項目中再遇到同類問題時,應該不會再毫無頭緒了。
來源:PHP教程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章