天天看點

淺析Ajax跨域原理及JQuery中的實作分析

  AJAX 的出現使得網頁可以通過在背景與伺服器進行少量資料交換,實作網頁的局部重新整理。但是出于安全的考慮,ajax不允許跨域通信。如果嘗試從不同的域請求資料,就會出現錯誤。如果能控制資料駐留的遠端伺服器并且每個請求都前往同一域,就可以避免這些安全錯誤。但是,如果僅停留在自己的伺服器上,Web 應用程式還有什麼用處呢?如果需要從多個第三方伺服器收集資料時,又該怎麼辦?

 一、關于ajax跨域的思考

  1、Ajax為什麼不能跨域?到底是卡在哪個環節了?(下面項目中具體說,這裡先說下結論)。 Ajax其實就是向伺服器發送一個GET或POST請求,然後取得伺服器響應結果,傳回用戶端。理論上這是沒有任何問題的,然而普通ajax跨域請求,在伺服器端不會有任何問題,隻是服務端響應資料傳回給浏覽器的時候,浏覽器根據響應頭的Access-Control-Allow-Origin字段的值來判斷是否有權限擷取資料,一般情況下,伺服器端如果沒有在這個字段做特殊處理的話,跨域是沒有權限通路的,是以響應資料被浏覽器給攔截了,是以在ajax回調函數裡是擷取不到資料的(來自園友補充)。是以現在ajax跨域的問題可以轉化為資料怎麼拿回用戶端的問題。

  2、既然不能直接通路第三方站點,我們可以在伺服器上面做代理,通過ajax向代理發送請求,代理獲得資料後在傳回給用戶端,當然這是一種解決辦法,但是一次請求要從用戶端經過代理到第三方站點,然後再原路傳回,響應速度是個問題。

  3、我們發現我們可以将一些js、css等檔案放在第三方的伺服器上面,如CDN等來加快網頁的打開速度,這樣是沒有任何問題的,也就是說web頁面可以加載放在任意站點的js、css、圖檔等資源,不會受到"跨域"的影響。這個時候,我們會想到:既然我們可以調用第三方站點的js,那麼如果我們将資料放到第三方站點的js中不就可以将資料帶到用戶端了嗎?

下面我們來做一個實驗,來驗證一下我們的猜想成不成立:

  打開Visual Studio,建立一個Web項目,這裡用WebForm,然後我們在項目中添加一個名為remoteJs的js檔案,寫入如下代碼:

很簡單,就一個方法,傳回一個字元串,下面我們來寫一個用戶端調用,既然是跨域,那就寫個html靜态頁面來測試吧,建立local.html,輸入以下代碼:

讓我們的Web項目跑起來,然後打開local.html,可以看到彈出一個視窗,顯示資訊remote data。這裡證明我們的想法是正确的。接下來的問題是,我們如何根據需要發送請求和擷取請求的結果呢?下面我們來認識一下JSONP。

 二、JSONP

 1、什麼是JSONP

  JSONP(JSON with Padding)是JSON的一種“使用模式”,可用于解決主流浏覽器的跨域資料通路的問題。其核心思想是利用JS标簽裡面的跨域特性進行跨域資料通路,在JS标簽裡面存在的是一個跨域的URL,實際執行的時候通過這個URL獲得一段字元串,這段傳回的字元串必須是一個合法的JS調用,通過EVAL這個字元串來完成對獲得的資料的處理。

  JSONP是一個非官方的協定,它允許在伺服器端內建Script tags傳回至用戶端,通過javascript callback的形式實作跨域通路(這僅僅是JSONP簡單的實作形式)。

2、JSONP的實作

  下面我們通過一個例子來說明一下JSONP是如何實作ajax跨域請求的。這裡我們模拟圖書館圖書的查詢,在剛剛我們建立的web項目裡面添加一個名為SearchBook的一般處理程式,寫入如下代碼:

暫時先不解釋,我們寫完用戶端看到效果後在詳細說明,然後修改剛剛的local.html,代碼如下:

這個html頁面有一個按鈕,綁定方法GetAjaxData,當我們單擊發送請求時,就會向Web站點發送請求,擷取查詢的資料,我們讓Web站點跑起來,然後打開local.html,單擊按鈕,看到彈出如下資訊:

淺析Ajax跨域原理及JQuery中的實作分析

我們成功的取得了web站點的資料,實作了跨域請求。下面我們來說一下他的實作原理:

這一行代碼我們定義了請求的url,問号前面的是web站點一般處理程式SearchBook的位址,問号後面我們傳入了一個參數callback,值為GetData,也就是我們上面定義的方法名,及回調函數名稱。當然我們可以傳入更多的參數。

這三行代碼就是添加script節點,url指向第三方站點,執行結果如圖:

淺析Ajax跨域原理及JQuery中的實作分析

那麼我們剛剛寫的一般處理程式傳回的結果就不用說了吧,他就是傳回一個字元串,内容為:

淺析Ajax跨域原理及JQuery中的實作分析

看到這裡清楚了吧,就是第三方站點生成一個對回調函數的調用,傳入查詢結果,然後通過<script>加載到用戶端執行。看到這裡是不是想到了什麼?是不是和C#裡面的委托有些共同點?整體流程如圖:

淺析Ajax跨域原理及JQuery中的實作分析

可以看到,整個過程,本地站點一直處于主動的地位,主動的發送請求,主動的加載遠端js.而第三方站點則處于被動的響應。

3、普通Ajax請求在哪個環節出錯了

下面,我們用JQuery的ajax來說明一下ajax請求到底是卡在哪個環節了,修改GetAjaxData方法如下:

在SearchBook裡面context.Response.Write(callback + "({'BookName':'English','Pages':562})");這行下端點,然後運作,會發現可以走到斷點,然後就出錯了。

4、用JQuery實作ajax跨域

其實JQuery裡面也封裝了跨域的ajax方法,我們來看一下上面的方法用JQuery怎麼寫:

注意,JQuery寫法裡面Url後面就不用再寫?來傳遞參數了,jsonp的值相當于?後面的值及參數名稱,jsonpCallback的值就是參數的value.success就是執行成功後調用的方法。

哎,不對啊,怎麼沒有GetData方法了?JQuery到底是怎麼實作的呢?下面我們來調試一下JQuery,來看一下裡面是怎麼實作的,調試js,當然還是要用Chrome,看圖:

淺析Ajax跨域原理及JQuery中的實作分析

這張圖中,我們看到有個對象s,在做url拼接操作,看到選中那行了吧,?後面拼的是s.jsonp,最後拼接的是callbackName.繼續向下走:

淺析Ajax跨域原理及JQuery中的實作分析

我們看到s.url的值,為拼接後的值,是不是和我們自己寫的js代碼裡面的url一模一樣,繼續向下走:

淺析Ajax跨域原理及JQuery中的實作分析

我們看到JQuery又在剛剛的url後面添加下劃線等号,然後又跟了一串數字,至于什麼用,我也說不上來,繼續向下走:

淺析Ajax跨域原理及JQuery中的實作分析

看到了什麼,success方法,哈哈,這是JQuery在變量參數,繼續走:

淺析Ajax跨域原理及JQuery中的實作分析

看到什麼了?沒錯,這就是JQuery最終調用的方法,最後一行代碼,添加了script節點,和我自己寫js實作的原理一樣。繼續向下走,看看還有什麼:

淺析Ajax跨域原理及JQuery中的實作分析

看到JQuery執行完後,又删除了剛剛添加的script節點,還是JQuery想的周到啊~~ 

 下面我們來看一下,我們自己寫的js執行後的DOM結構:

淺析Ajax跨域原理及JQuery中的實作分析

看到了吧,script節點會随着請求的次數一路飙升,不過并不會引起錯誤,重新整理後就消失了。而JQuery執行後,DOM結構是不變的。

 三、總結

    1、ajax和jsonp這兩種技術在調用方式上“看起來”很像,目的也一樣,都是請求一個url,然後把伺服器傳回的資料進行處理,是以jquery和ext等架構都把jsonp作為ajax的一種形式進行了封裝;

  2、ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest擷取非本頁内容,而jsonp的核心則是通過HTTP來動态添加<script>标簽來調用伺服器提供的js腳本。

  3、其實ajax與jsonp的差別不在于是否跨域,ajax通過服務端代理一樣可以實作跨域,jsonp本身也不排斥同域的資料的擷取。

  4、jsonp是一種方式或者說非強制性協定,如同ajax一樣,它也不一定非要用json格式來傳遞資料,如果你願意,字元串都行,隻不過這樣不利于用jsonp提供公開服務。

  5、jsonp整個過程中,本地站點一直處于主動的地位,主動的發送請求,主動的加載遠端js.而第三方站點則處于被動的響應。

QQ交流群:243633526

 部落格位址:http://www.cnblogs.com/yunfeifei/

 聲明:本部落格原創文字隻代表本人工作中在某一時間内總結的觀點或結論,與本人所在機關沒有直接利益關系。非商業,未授權,貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。

如果大家感覺我的博文對大家有幫助,請推薦支援一把,給我寫作的動力。

繼續閱讀