js便籤筆記(13)——jsonp其實很簡單【ajax跨域請求】

王福朋發表於2014-10-30

前兩天被問到ajax跨域如何解決,還真被問住了,光知道有個什麼jsonp,迷迷糊糊的沒有說上來。抱著有問題必須解決的態度,我看了許多資料,原來如此。。。

為何一直知道jsonp,但一直迷迷糊糊的不明白呢?——網上那些介紹資料都寫的太複雜了!

我是能多簡單就多簡單,爭取讓你十分鐘看完!

1. 同源策略

ajax之所以需要“跨域”,罪魁禍首就是瀏覽器的同源策略。即,一個頁面的ajax只能獲取這個頁面相同源或者相同域的資料

如何叫“同源”或者“同域”呢?——協議、域名、埠號都必須相同。例如:

http://google.com  和  https://google.com 不同,因為協議不同;

http://localhost:8080  和  http://localhost:1000 不同,因為埠不同;

http://localhost:8080  和  https://google.com 不同,協議、域名、埠號都不同,根本不是一家的。

根據同源策略,我自己做的一個網頁 http://localhost:8080/test.html 就無法通過ajax直接獲取 http://google.com 的資料。

例如,我用ajax去訪問一個不同域的頁面,錯誤結果是這樣的:

 

大家想想,這樣其實也有道理。如果沒有同源策略,你我都可以隨便通過ajax直接獲取其他網站的資訊,這還不亂套了。。。我自己做一個搜尋介面,搜尋時直接用ajax從百度獲取資料,那不成了小偷了。。。

但是跨域訪問是少不了的,mail.163.com 的網頁可能需要從 news.163.com 域下獲取新聞資訊,那怎麼辦?——開始我們們的跨域之旅(當然用iframe也可以實現)

2. 從“盜鏈”說起

網際網路的許多網站之間圖片相互盜鏈,A網站網頁的img.src直接連結到B網站的圖片地址,這是常有的事兒。說到“盜鏈”,大家第一想到的可能是如何去防止盜鏈,今兒我們不管那個。

你再想想“盜鏈”和“同源策略”這兩個詞之間有什麼關係?——對,矛盾!既然都“同源策略”了,怎麼還能“盜鏈”呢?

世間萬物都有矛盾,有矛盾了照樣可以和諧共處,並不一定非要你死我活。

重點:<img>的src(獲取圖片),<link>的href(獲取css),<script>的src(獲取javascript)這三個都不符合同源策略,它們可以跨域獲取資料。因此,你可以直接從一些cdn上獲取jQuery,並且你網站上的圖片也隨時可能被別人盜用,所有最好加上水印!

而我們今天的主角——jsonp——就是因為<script>的src不符合同源策略而來的

3. JSONP

例如,域名 a.com 下有一個 a.com/test.html 網頁,域名 b.com 下有一個 b.com/data.html 網頁和 b.com/alert.js 檔案。

引導第一步:簡單引用js

編寫 b.com/alert.js 如下:

alert(123);

對 a.com/test.html 編寫如下程式碼:

<script type='text/javascript' src='http://b.com/alert.js'/>

執行 a.com/test.html,結果很明顯,就是彈出 【123】 。

 

引導第二步:引用js返回資料

將 b.com/alert.js 修改為:

myFn(100);

將 a.com/test.html 修改為:

<script>
    function myFn ( data ) {
        alert( data + 'px' );
    }
</script>
<script type='text/javascript' src='http://b.com/alert.js'/>

執行 a.com/test.html,結果是彈出【 100px 】,這個應該也沒有什麼疑問。

 

引導第三步:已經跨域成功!

第二步中,如果data——即100——是我要跨域在b.com下獲取的一個資料,那麼我們們這不就是已經實現跨域請求了嗎!!!

把這個過程再清晰的捋一遍:

  • <script>的src不符合同源策略;
  • 我通過給<script>的src賦值一個跨域的檔案的網址(可能不是一個js檔案),這個檔案返回的字串,瀏覽器會當作javascript來解析;
  • 而這段javascript中,就可以包含著我所需要的跨域伺服器端的資料;
  • 最後,我在本頁面定義一個myFn函式用來展示資料,而這段javascript中就可以直接呼叫myFn函式;

 

引導第四步:引用html格式

<script>的src不一定僅僅指向javascript檔案,可以指向任何地址。例如:

將 a.com/test.html 修改為:

<script>
    function myFn ( data ) {
        alert( data + 'px' );
    }
</script>
<script type='text/javascript' src='http://b.com/data.html'/>

將 b.com/data.html 編寫為:(注意,data.html中就寫以下一行程式碼,多了不寫)

myFn(100); 

執行 a.com/test.html ,結果依然是【 100px 】

其中,“100”就是我們要跨域請求的資料。

 

引導第五步:動態資料

如果要請求的資料是動態的,那就要在動態頁面中編寫。

那麼我們就讓 a.com/test.html 去呼叫一個動態的aspx頁面:

<script>
    function myFn ( data ) {
        alert( data + 'px' );
    }
</script>
<script type='text/javascript' src='http://b.com/data.aspx?callback=myFn'/>

大家注意,我們在 src 地址中增加了“?callback=myFn”,意思是把顯示資料的函式也動態傳過去了,而第二步、第四步都是靜態的寫在被呼叫的檔案中的。

至於callback引數後臺如何接收,如何使用,請接著看:

在 b.com 下增加一個 b.com/data.aspx 頁面,後臺程式碼如下:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (this.IsPostBack == false)
        {
            string callback = "";
            if (Request["callback"] != null)
            {
                callback = Request["callback"];

                //伺服器端要返回的資料
                string data = "1024";

                Response.Write(callback + "(" + data + ")");
            }
        }
    }

程式碼很簡單,獲取callback引數,然後組成一個函式的形式返回。如果“b.com/data.aspx?callback=myFn”呼叫的話,那麼返回的就是" myFn(1024) "。

返回的資料變成動態的了(“1024”),前端頁面用於顯示資料的函式也程式設計了動態的了(“callback=myFn”),但是歸根結底,形式還是一樣的。

 

引導第六步:呼叫封裝

a.com/test.html 中,僅僅有一個<script>靜靜的躺在那裡,執行一次之後,就沒有作用了。

而實際情況是,a.com/test.html 中,可能隨著使用者的操作發生若干次的呼叫。怎麼辦?——動態增加唄。

function addScriptTag(src) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.src = src;
    document.body.appendChild(script);
}

function myFn (data) {
    alert(data + 'px');  
}

//需要呼叫時:
//addScriptTag('b.com/data.aspx?callback=myFn');

 

4. 總結

以上層層描述的就是JSONP,你不必去記住它的定義,看明白了上述文字,就全能理解。

重點在於:同源策略 + <script>的src不屬於同源策略 + 通過<script>的src指向的檔案返回伺服器端資料

ok,就這些!

-------------------------------------------------------------------------------------------------------------

歡迎關注我的微博

也歡迎關注我的其他教程:

從設計到模式深入理解javascript原型和閉包系列微軟petshop4.0原始碼解讀視訊》《json2.js原始碼解讀視訊

相關文章