1. 程式人生 > >學習 同源策略,jsonp,跨域 隨記

學習 同源策略,jsonp,跨域 隨記

  1. 同源策略不阻止將動態指令碼元素插入文件中

   2.注意:jquey是不支援post方式跨域的。 

   為什麼呢?
雖然採用post +動態生成iframe是可以達到post跨域的目的,但這樣做是一個比較極端的方式,不建議採用.
也可以說get方式的跨域是合法的,post方式從安全形度上,被認為是不合法的, 萬不得已還是不要劍走偏鋒..

client端跨域訪問的需求看來也引起w3c的注意了,看資料說html5 WebSocket標準支援跨域的資料交換,應該也是一個將來可選的跨域資料交換的解決方案


   

      理解跨域首先必須要了解同源策略。同源策略是瀏覽器上為安全性考慮實施的非常重要的安全策略。


   何謂同源:

        URL由協議、域名、埠和路徑組成,如果兩個URL的協議、域名和埠相同,則表示他們同源

 什麼是跨域?

       概念:只要協議、域名、埠有任何一個不同,都被當作是不同的域

   

   a.同源策略

;

JS只能與同一個域中的頁面進行通訊.:執行在 http://domain:port/app1/page.html;上的指令碼不能和http://domain:port/app3/page.html;的瀏覽器視窗或iframe 進行互動.不能訪問它的cookie,接收它的HTTP響應等(但它可以向任何其他源傳送HTTP請求);AJAX  webservice 也受此策略管束.這種手段就叫同源策略;

兩個指令碼被認為是同源的條件是:

 

協議相同(比如都是http://)   ;埠相同(通常都是80)  域名相同;

 

如果這三個條件中有任何一條不滿足,就不允許兩個指令碼進行互動.:www.mydomain.com上的指令碼不能訪問video.mydomain.com上的頁面 ,因為兩者的域名不同,雖然後者是前者的子域.同樣,它也不能訪問www.mydomain.com:8080上的頁面 ,因為埠不同,也不能訪問about:blank 因為協議不同(後者不是http://)



跨域資源共享(CORS

CROSCross-Origin Resource Sharing)跨域資源共享,定義了必須在訪問跨域資源時,瀏覽器與伺服器應該如何溝通。CROS背後的基本思想就是使用自定義的HTTP頭部讓瀏覽器與伺服器進行溝通,從而決定請求或響應是應該成功還是失敗。




什麼是jsonp

       維基百科的定義是:JSONPJSON with Padding)是資料格式 JSON 的一種使用模式,可以讓網頁從別的網域要資   料。

      JSONP也叫填充式JSON,是應用JSON的一種新方法,只不過是被包含在函式呼叫中的JSON,例如:


     callback({"name","trigkit4"});

      JSONP由兩部分組成:回撥函式和資料。回撥函式是當響應到來時應該在頁面中呼叫的函式,而資料就是傳入回撥函式中的JSON資料。

    在js中,我們直接用XMLHttpRequest請求不同域上的資料時,是不可以的。但是,在頁面上引入不同域上的js指令碼檔案卻是可以的,jsonp正是利用這個特性來實現的。

   例如:

   <script type="text/javascript">

    function dosomething(jsondata){

        //處理獲得的json資料

    }

</script>

<script src="http://example.com/data.php?callback=dosomething"></script>


    js檔案載入成功後會執行我們在url引數中指定的函式,並且會把我們需要的json資料作為引數傳入。所以jsonp是需要伺服器端的頁面進行相應的配合的。 

   

<?php

$callback = $_GET['callback'];//得到回撥函式名

$data = array('a','b','c');//要返回的資料

echo $callback.'('.json_encode($data).')';//輸出

?>

最終,輸出結果為:dosomething(['a','b','c']);


如果你的頁面使用jquery,那麼通過它封裝的方法就能很方便的來進行jsonp操作了。

<script type="text/javascript">

    $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){

        //處理獲得的json資料

    });

</script>

jquery會自動生成一個全域性函式來替換callback=?中的問號,之後獲取到資料後又會自動銷燬,實際上就是起一個臨時代理函式的作用。$.getJSON方法會自動判斷是否跨域,不跨域的話,就呼叫普通的ajax方法;跨域的話,則會以非同步載入js檔案的形式來呼叫jsonp的回撥函


JSONP的優缺點

JSONP的優點是:它不像XMLHttpRequest物件實現的Ajax請求那樣受到同源策略的限制;它的相容性更好,在更加古老的瀏覽器中都可以執行,不需要XMLHttpRequestActiveX的支援;並且在請求完畢後可以通過呼叫callback的方式回傳結果。

JSONP的缺點則是:它只支援GET請求而不支援POST等其它型別的HTTP請求;它只支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript呼叫的問題。


Jsonp原理:

首先在客戶端註冊一個callback (:'jsoncallback'), 然後把callback的名字(:jsonp1236827957501)傳給伺服器。注意:服務端得到callback的數值後,要用jsonp1236827957501(......)把將要輸出的json內容包括起來,此時,伺服器生成 json 資料才能被客戶端正確接收。

然後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的引數 'jsoncallback'的值 jsonp1236827957501 .

最後將 json 資料直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文件,返回給客戶端。

客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文件,此時javascript文件資料,作為引數,
傳入到了客戶端預先定義好的 callback 函式(如上例中jquery $.ajax()方法封裝的的success: function (json)).(動態執行回撥函式)

可以說jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空間就是大量採用這種方式來實現跨域資料交換的) .JSONP是一種指令碼注入(Script Injection)行為,所以也有一定的安全隱患.


jsonp的原理:


首先在客戶端註冊一個callback (:'jsoncallback'), 然後把callback的名字(:success_jsonpCallback)傳給伺服器端對應的處理函式。

伺服器先生成需要返回給客戶端的 json 資料。然後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的引數(jsoncallback)的值(success_jsonpCallback)

最後將 json 資料直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文件,返回給客戶端。
客戶端瀏覽器,解析script標籤,並將伺服器端返回的資料,作為引數,
傳入到了客戶端預先定義好的 callback 函式(如上例中jquery $.ajax()方法封裝的的success: function (json))裡。

實際上跨域是通過動態增加script來載入資料,無法直接獲得資料,所以需要使用回撥函式。


執行原理:


傳送請求時需要傳一個callback的回撥函式名到伺服器端,伺服器端拿到這個回撥函式名,再將返回資料用引數的形式反回到客戶端,這樣客戶端就能夠調到。

所以傳送請求URL的地址後面一定要上jsoncallback=?這樣的引數,jquery會將?號自動替換成自動生成的回撥函式的名稱。

所以最終的實際請求為:http://api.taobao.com/apitools/ajax_props.do&jsoncallback=jsonp1322444422697

所以和ajax的方式想比較,也就是callback函式一個是自動生成的函式名,一個是手工指定的函式名




原理的示例程式碼:

//客戶端的JAVASCRIPT程式碼 

var script=document.createElement("script"); 

script.src="http://www.pl4cj.com:8888/5/6/action.php?param=123&callback="+fnName; 

document.getElementsByTagName("head")[0].appendChild(script) 


//伺服器端的PHP程式碼,一定要有callback來進行回撥,在這裡加上括號,是讓它以語句塊的方式來進行解析 

<?php 

<SPAN style="COLOR: #ff00ff">echo $_GET["callback"]."(".json_encode($_GET).");"; 

</SPAN>?