javascript 跨域請求詳細分析

什麼是跨域請求

比如用戶使用瀏覽器打開一個網站 (www.AAA.com)的首頁,這個時候瀏覽器會執行來自網站www.AAA.com的一個javascript的函數,這個函數是向網站(www.BBB.com)請求數據:
$.getJSON('www.BBB.com/index.php', funciton(data) {
    // 後續操作
});
網站A的腳本去請求網站B的數據,就是跨域請求。在沒有處理的情況下,瀏覽器會限制這樣的請求。

同源策略

同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。這個策略可以追溯到 Netscape Navigator 2.0。如果兩個頁面的協議端口(如果指明瞭的話)和主機名都相同,Mozilla 認爲這兩個頁面擁有相同的源。瀏覽器爲什麼要做這樣的限制呢?
我們知道,JAVASCRIPT是很強大的,比如你打開了一個支付寶的網頁,又一不小心打開了一個“病毒”網頁,這個網頁有一段Javascript,執行這段JS後,會修改了你的支付寶頁面,後果可想而知。所以,瀏覽器阻止javascript請求非同源的腳本數據。

什麼情況下,我們要繞過瀏覽器這個限制

情況1:CDN緩存導致的跨域請求。CDN服務器可以緩存網站服務器的javascript 文件,當瀏覽器向服務器請求數據的時候,如果需要請求javascript文件,瀏覽器首先會去CDN服務器中要,然後再由CDN服務器去網站服務器拿。加入一個CDN緩存後,就可以避免每次都向服務器某些文件。但是這樣做,會有一個嚴重的問題,因爲javascript文件是從CDN服務器中拿的,如果這個javascript需要向網站服務器請求數據,就會涉及到跨域的問題。

情況2:使用HTML構建APP應用,如果APP應用會有很多圖片和文件,每次請求都向服務器請求這些圖片和文件,實現的效果肯定不理想,而且特別耗流量.爲了解決這個問題,我們可以把javascript保存在本地,然後通過訪問文件的協議訪問js文件,由這些js文件請求服務器的數據,更加數據的要求動態的構建html頁面。訪問形式類似與:
file:///E:/BaiduYunPan/www/test.js

情況3:網站A和網站B都是我的,我需要網站A中的Javascript能請求網站B的數據。

如何繞過瀏覽器這個限制

javascript 中src屬性是不受同源策略限制的,因爲這樣,我們可以引用谷歌提供的Jquery文件。而且還記住一點,由src請求回來的數據,瀏覽器默認它是一段可執行的JS文件。在網站A中一個test.js:
<html>
<script>
function test(data)
{
    alert(data);
}
</script>
<script type="text/javascript" src="http://www.BBB.com/test.php"></script>
</html>

注意:test()函數必須聲明在前。在網站B中有這個test.php文件:
<?php
echo "test('this data is from Server B')";

當瀏覽器執行到tes.js文件的時候,會觸發test(data)這個函數,也就是說,可以請求到網站B的內容。這樣,我們就已經實現了跨域請求數據。這個原理就是 src不受同源策略限制,會獲取網站B響應的數據,而且會把這個數據當做JS文件來執行,所以,對於網站A來說,就是執行了test(data)函數。這個實現方式的重點就是網站B響應的數據是網站A中一段可執行的JS文件,這樣網站A就可以處理來自網站B的數據了。

ajax自帶jsonp屬性實現跨域請求

jquery自帶的ajax可以實現跨域請求,需求還是網站A中javascript向網站B請求數據。網站A中test.js的代碼可以這樣寫:
   $.ajax({
        url:"www.BBB.com/index.php",   
        dataType:"jsonp",
        jsonpCallback:"person",
        success:function(data){
            alert(data.name + " is a a" + data.sex);
        }
   });
在網站B中有一個index.php文件
echo 'person(' . json_encode(array('name' => 'sunli', 'age' => '24')) . ')';
這樣就可以。

需要注意的是:
(1)jsonpCallback屬性如果不指定,那麼會有個隨機的函數名, index.php輸出數據的時候應該是這樣:
echo $_GET['callback'] . '(' . json_encode(array('name' => 'sunli', 'age' => '24')) . ')';

 (2)我在實現jsonp的時候,沒有填寫jsonpCallback, 在index.php中也沒有加入$_GET['calllback']這樣的函數名,於是就遇到一個很大的錯誤,網站A依然可以請求到網站B的數據,但是,test.js文件中,success 響應函數沒有執行到,我想了半天都沒有想到,爲什麼瀏覽器成功響應了數據,但是success卻沒有執行,最後由老大指出了問題,就是我第一點說的,沒有指定回調函數,就算數據返回過來了,也不會執行success.





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章