跨域問題產生的緣由,是因爲瀏覽器的安全機制,JS只能訪問與所在頁面同一個域(相同協議、域名、端口)的內容。html
可是咱們項目開發過程當中,常常會遇到在一個頁面的JS代碼中,須要經過AJAX去訪問另外一個服務器並返回數據,這時候就會受到瀏覽器跨域的安全限制了。html5
這裏要注意,若是隻是經過AJAX向另外一個服務器發送請求而不要求數據返回,是不受跨域限制的。瀏覽器只是限制不能訪問另外一個域的數據,即不能訪問返回的數據,並不限制發送請求。jquery
咱們接下來就爲你們講解最多見的跨域AJAX調用的解決方案,首先咱們先準備一個測試環境:web
127.0.0.1 www.aaa.com
127.0.0.1 www.bbb.comajax
啓動Tomcat後,在瀏覽器中,分別測試編程
http://www.aaa.com:8080/test-client/index.htmljson
http://www.bbb.com:8080/test-client/index.html後端
兩個頁面是相同的,只是地址不一樣,都是在點擊按鈕後經過AJAX去訪問http://www.bbb.com:8080/test-service/add.jsp。可是從www.aaa.com:8080訪問時就返回了error,即瀏覽器不容許在www.aaa.com:8080的頁面中經過AJAX獲取來自www.bbb.com:8080服務器的返回數據。跨域
你們觀察一下Tomcat控制檯,會發現從www.aaa.com:8080訪問時,雖然返回了錯誤,但服務端代碼其實仍是執行了。這個現象驗證了跨域是能夠發請求的,可是瀏覽器出於安全的緣由不讓咱們在JS中獲取返回數據。瀏覽器
測試案例很簡單,就是傳入a=15&b=10兩個參數,返回兩個數據的和25,代碼參見:
test-client/index.html
test-service/add.jsp
本節介紹的CORS(Cross-Origin Resource Sharing)方案是W3C在2014年正式推出的跨域訪問方案,是真正的官方解決方案。這個方案的實現很是簡單,只須要在服務端返回的頭部信息中標明是否容許跨域訪問,以及容許哪些域訪問便可。
接下來咱們訪問
http://www.aaa.com:8080/test-client/index_cors.html
成功了!!!咱們來看代碼中有什麼改變?
index_cors.html與index.html的差別僅是ajax調用的地址從add.jsp換成了add_cors.jsp,咱們再來看add.jsp和add_cors.jsp的區別,會發現只增長了一行代碼:
response.setHeader(「Access-Control-Allow-Origin」, 「http://www.aaa.com:8080」);
若是不限定跨域訪問的地址,能夠把域名部分設置爲*:
response.setHeader(「Access-Control-Allow-Origin」, 「*」);
小結:
CORS方案實現很是簡單,只要服務在頭部標明容許跨域訪問便可。可是這個方案因爲推出時間較晚,因此IE9及如下瀏覽器並無支持這個機制。
IE9及如下瀏覽器在安全設置裏控制是否容許跨域數據訪問:
默認是上面的選項是禁用的,須要手動啓用。同時,因爲jQuery自動判斷並認爲當前瀏覽器不支持跨域,因此咱們還須要用一行代碼讓jquery支持跨域ajax:
$.support.cors = true;
JSONP並非一個官方協議,其本質上是一種巧妙的跨域獲取JSON數據的編程技巧。
咱們首先來看實現,JSONP在實現上要比CORS稍微麻煩一點點,先後端要有點配合。
首先運行http://www.aaa.com:8080/test-client/index_jsonp.html,這個頁面裏面AJAX後端請求換成了add_jsonp.jsp。
接下來咱們先解析代碼:
index_jsonp.html中,咱們在$.ajax的參數上有點變化:
add_jsonp.jsp中,咱們在最後數據返回部分作了一點處理:
先後端須要作的工做就是這麼多,可是這時候初學者必定以爲有點迷惑了,這個回調函數名究竟是幹什麼用的?咱們並無定義什麼回調函數啊?它是怎麼工做的呢?
咱們簡單的加一個調試很快就能夠解開這個疑惑,在add_jsonp.jsp最終返回的數據中加一個debugger:
String jsonpResult = String.format(「debugger;%s(%s)」, callbackName, jsonResult);
接下來咱們F12啓動瀏覽器開發者工具,點擊按鈕後就會進入JS調試。
這時候咱們看到返回的是一個JS函數的調用,函數名是隨機的,函數的參數就是那個咱們構造的JSON。接下來,咱們在控制檯輸入window.函數名,會發現這個函數是真實存在的!!!
這是怎麼回事呢???原來jQuery所謂的JSONP模式,實際上是動態建立了一個<script>標籤,標籤的src屬性指向一個URL(http://www.bbb.com:8080/test-service/add_jsonp.jsp?x5callback=jQuery18203749695811420679_1439276096319&a=15&b=10&_=1439276101932),這個URL裏面除了包含咱們的a和b兩個參數,還包含一個x5callback參數,參數的值就是那個隨機的函數名。這個script標籤動態插入到當前頁面後,天然就會將咱們返回的內容當作JS加載到當前頁面(這裏咱們返回的是JS,瀏覽器是不阻止的哦,頁面能夠從任何域加載JS腳本):
debugger;jQuery18203749695811420679_1439276096319({「sum」: 25})
加載後,按照JS的特性,這些代碼會當即執行。而jQuery在這個以前已經動態建立了一個以隨機函數名爲名稱的全局函數,用於接收返回數據,再日後jQuery經過一系列的邏輯代碼最終把返回值給到了咱們的success回調函數中。
有關jQuery動態建立<script>相關的邏輯,你們能夠在咱們案例自帶的jquery-1.8.2.js的8270行加上斷點進行跟蹤。
小結:
JSONP是以動態建立script標籤爲基礎的一種編程技巧,來實現跨域獲取JSON數據。
支持目前全部瀏覽器,只是在實現方式上須要先後端代碼有一點約定配合。
可是,要注意因爲JSONP是以script標籤的src屬性加載的,所以參數會收到URL長度的限制,只能適用於傳入參數內容很少的場景。
CORS方案實現簡單,同時支持GET和POST請求,可是不支持IE9及如下瀏覽器。這時看官要問了,這麼多瀏覽器不支持,這技術怎麼用啊?手機啊!目前市面上全部的手機瀏覽器是所有支持CORS的,若是是爲手機提供跨域服務CORS就夠了。
JSONP方案實現須要先後端配合,支持GET請求,支持全部瀏覽器,只是傳入的參數內容受限於URL長度限制。
下載資源:ajax-cors-jsonp.zip
本文由WeX5君整理,WeX5一款開源免費的html5開發工具,H5 App開發就用WeX5!
閱讀其餘app 開發相關文章:http://doc.wex5.com/?p=3443