前端跨域問題相關知識詳解(原生js和jquery兩種方法實現jsonp跨域)

一、同源策略javascript

同源策略(Same origin policy),它是由Netscape提出的一個著名的安全策略。同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現,如今全部支持JavaScript 的瀏覽器都會使用這個策略。php

所謂同源,就是指兩個頁面具備相同的協議,主機(也常說域名),端口,三個要素缺一不可。css

所謂同源策略,指的是瀏覽器對不一樣源的腳本或者文本的訪問方式進行的限制。即a.com 域名下的js沒法操做b.com或是c.com域名下的對象。詳細見下表:html

URL1 URL2 說明 是否容許通訊
http://www.foo.com/js/a.js http://www.foo.com/js/b.js 協議、域名、端口都相同 容許
http://www.foo.com/js/a.js http://www.foo.com:8888/js/b.js 協議、域名相同,端口不一樣 不容許
https://www.foo.com/js/a.js http://www.foo.com/js/b.js 主機、域名相同,協議不一樣 不容許
http://www.foo.com/js/a.js http://www.bar.com/js/b.js 協議、端口相同,域名不一樣 不容許
http://www.foo.com/js/a.js http://foo.com/js/b.js 協議、端口相同,主域名相同,子域名不一樣 不容許

 

URL 說明 是否容許通訊
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 容許
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不一樣文件夾 容許
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不一樣端口 不容許
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不一樣協議 不容許
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名對應ip 不容許
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不一樣 不容許
http://www.a.com/a.js
http://a.com/b.js
同一域名,不一樣二級域名(同上) 不容許(cookie這種狀況下也不容許訪問)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不一樣域名 不容許
eg:當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪一個頁面的,即檢查是否同源,只有和百度同源的腳本纔會被執行。若是非同源,那麼在請求數據時,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。
特別注意兩點:
第一,若是是協議和端口形成的跨域問題「前臺」是無能爲力的;
第二:在跨域問題上,域僅僅是經過「URL的首部」來識別而不會去嘗試判斷相同的ip地址對應着兩個域或兩個域是否在同一個ip上。
「URL的首部」指window.location.protocol +window.location.host,也能夠理解爲「Domains, protocols and ports must match」。

    前端所說的跨域通常指「前臺」處理跨域的辦法,後臺proxy這種方案牽涉到後臺配置,有興趣的能夠參考yahoo的這篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls前端

同源策略限制了不一樣源之間的交互,可咱們平時文件中引用其餘域名的js文件,css文件,圖片文件爲什麼沒受到限制呢?同源策略限制的不一樣源之間的交互主要針對的是js中的XMLHttpRequest等請求,下面這些狀況是徹底不受同源策略限制的:java

  • 頁面中的連接,重定向以及表單提交是不會受到同源策略限制的。連接就不用說了,導航網站上的連接都是連接到其餘站點的。而你在域名www.foo.com下面提交一個表單到www.bar.com是徹底能夠的。
  • 跨域資源嵌入是容許的,固然,瀏覽器限制了Javascript不能讀寫加載的內容。如前面提到的嵌入的<script src="..."></script>,<img>,<link>,<iframe>等。固然,若是要阻止iframe嵌入咱們網站的資源(頁面或者js等),咱們能夠在web服務器加上一個X-Frame-Options DENY頭部來限制。nginx就能夠這樣設置add_header X-Frame-Options DENY;

互聯網的許多網站之間圖片相互盜鏈,A網站網頁的img.src直接連接到B網站的圖片地址,就是由於這個緣由:<img>的src(獲取圖片),<link>的href(獲取css),<script>的src(獲取javascript)這三個都不符合同源策略,它們能夠跨域獲取數據。所以,你能夠直接從一些cdn上獲取jQuery,而且你網站上的圖片也隨時可能被別人盜用。jquery

而咱們的第一種跨域方法jsonp,就是由於<script>的src不符合同源策略而來的。nginx

二、解決跨域問題-JSONP web

Asynchronous JavaScript and XML (Ajax ) 是驅動新一代 Web 站點(流行術語爲 Web 2.0 站點)的關鍵技術。Ajax 容許在不干擾 Web 應用程序的顯示和行爲的狀況下在後臺進行數據檢索。使用 XMLHttpRequest 函數獲取數據,它是一種 API,容許客戶端 JavaScript 經過 HTTP 鏈接到遠程服務器。Ajax 也是許多 mashup 的驅動力,它可未來自多個地方的內容集成爲單一Web 應用程序。ajax

不過,因爲受到瀏覽器的限制,該方法不容許跨域通訊。

即:當咱們利用XMLHttpRequest對象從本地服務器獲取數據時是能夠的,可是它不容許跨服務器發送請求。既然XMLHttpRequest由於考慮到安全性不容許發送請求到外部服務器,只好尋找其它的辦法。(見2.2。

說到AJAX首先要思考的兩個問題,第一個是AJAX以何種格式來交換數據?第二個是跨域的需求如何解決?這兩個問題目前都有不一樣的解決方案,好比數據能夠用自定義字符串或者用XML來描述,跨域能夠經過服務器端代理來解決。但到目前爲止最被推崇或者說首選的方案仍是用JSON來傳數據,靠JSONP來跨域。

JSON(JavaScript Object Notation)和JSONP(JSON with Padding)雖然只有一個字母的差異,但其實他們根本不是一回事兒:JSON是一種數據交換格式,而JSONP是一種依靠開發人員的聰明才智創造出的一種非官方跨域數據交互協議。咱們拿最近比較火的諜戰片來打個比方,JSON是地下黨們用來書寫和交換情報的「暗號」,而JSONP則是把用暗號書寫的情報傳遞給本身同志時使用的接頭方式。看到沒?一個是描述信息的格式,一個是信息傳遞雙方約定的方法。

2.1 JSON

JSON:javaScript對象表示法(JavaScript Object Notation)

JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the language with no muss or fuss.

 JSON是一種輕量級的數據交換格式。(json.org

JSON是存儲和交換文本信息的語法,相似XML。它採用鍵值對的方式來組織,易於人們閱讀和編寫,同時也易於機器解析和生成。JSON是獨立於語言的,也就是說無論什麼語言,均可以解析json,只須要按照json的規則來就行。

JSON語法規則:JSON可以以很是簡單的方式來描述數據結構,XML能作的它都能作,所以在跨平臺方面二者徹底不分伯仲。

(1)JSON只有兩種數據類型描述符,大括號{}和方括號[],其他英文冒號:是映射符,英文逗號,是分隔符,英文雙引號""是定義符。

(2)大括號{}用來描述一組「不一樣類型的無序鍵值對集合」(每一個鍵值對能夠理解爲OOP的屬性描述),方括號[]用來描述一組「相同類型的有序數據集合」(可對應OOP的數組)。

(3)上述兩種集合中如有多個子項,則經過英文逗號,進行分隔。

(4)鍵值對以英文冒號:進行分隔,而且建議鍵名都加上英文雙引號"",以便於不一樣語言的解析。

(5)JSON內部經常使用數據類型有字符串、數字、布爾、日期、null 等,字符串必須用雙引號引發來,其他的都不用,日期類型比較特殊,建議若是客戶端沒有按日期排序功能需求的話,那麼把日期時間直接做爲字符串傳遞就好,能夠省去不少麻煩。

json解析的方法有兩種:eval()和parse()方法。————建議儘可能使用JSON.parse方法來解析json裏的字符串。

JSON和XML比較:

(1)JSON的長度和XML格式比起來很短小;

(2)JSON讀寫的速度更快;

(3)JSON可使用JavaScript內建的方法直接進行解析,轉換成JavaScipt對象,很是方便

JSON的優勢:

(1)基於純文本,跨平臺傳遞極其簡單;

(2)Javascript原生支持,後臺語言幾乎所有支持;

(3)輕量級數據格式,佔用字符數量極少,特別適合互聯網傳遞;

(4)可讀性強,容易編寫和解析;

JSON的缺點:

(1)JSON在服務端語言的支持不像XML那麼普遍,不過JSON.org上提供不少語言的庫。

(2)若是你使用eval()來解析的話,會容易出現安全問題。

儘管如此,JSON的優勢仍是很明顯的。他是Ajax數據交互的很理想的數據格式。

2.2 JSONP

JSONP:JSON with Padding(填充式 JSON 或參數式 JSON)JSONP是一個非官方的協議,它容許在服務器端集成Script tags返回至客戶端,經過javascript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)

2.2.1 JSONP的產生

  一、一個衆所周知的問題,因爲同源策略,Ajax直接請求普通文件存在跨域無權限訪問的問題,甭管你是靜態頁面、動態網頁、web服務、WCF,只要是跨域請求,一概不許;

  二、不過咱們又發現,Web頁面上調用js文件時則不受是否跨域的影響(不只如此,咱們還發現凡是擁有」src」這個屬性的標籤都擁有跨域的能力,好比<script>、<img>、<iframe>);

  三、因而能夠判斷,當前階段若是想經過純web端(ActiveX控件、服務端代理、屬於將來的HTML5之Websocket等方式不算)跨域訪問數據就只有一種可能,那就是在遠程服務器上設法把數據裝進js格式的文件裏,供客戶端調用和進一步處理;

  四、恰巧咱們已經知道有一種叫作JSON的純字符數據格式能夠簡潔的描述複雜數據,更妙的是JSON還被js原生支持,因此在客戶端幾乎能夠爲所欲爲的處理這種格式的數據;

  五、這樣子解決方案就呼之欲出了,web客戶端經過與調用腳本如出一轍的方式,來調用跨域服務器上動態生成的js格式文件(通常以JSON爲後綴),顯而易見,服務器之因此要動態生成JSON文件,目的就在於把客戶端須要的數據裝入進去。

  六、客戶端在對JSON文件調用成功以後,也就得到了本身所需的數據,剩下的就是按照本身需求進行處理和展示了,這種獲取遠程數據的方式看起來很是像AJAX,但其實並不同。

  七、爲了便於客戶端使用數據,逐漸造成了一種非正式傳輸協議,人們把它稱做JSONP,該協議的一個要點就是容許用戶傳遞一個callback參數給服務端,而後服務端返回數據時會將這個callback參數做爲函數名來包裹住JSON數據,這樣客戶端就能夠隨意定製本身的函數來自動處理返回數據了。

一句話總結:因爲同源策略的限制,XmlHttpRequest只容許請求當前源(域名、協議、端口)的資源,爲了實現跨域請求,能夠經過script標籤實現跨域請求,而後在服務端輸出JSON數據並執行回調函數,從而解決了跨域的數據請求。

如下兩篇文章以淺顯按部就班的方式對jsonp的概念進行了闡釋,對理解其前因後果頗有幫助:

說說JSON和JSONP,也許你會豁然開朗

jsonp其實很簡單【ajax跨域請求】

 2.2.2 JSONP的實現

JSONP藉助了script標籤節點跨域訪問/獲取的特性。JSONP實現跨域請求的原理簡單的說,就是動態建立<script>標籤,而後利用<script>的src 不受同源策略約束來跨域獲取數據。

JSONP由兩部分組成:回調函數和數據。回調函數是當響應到來時應該在頁面中調用的函數。回調函數的名字通常是在請求中指定的。而數據就是傳入回調函數中的 JSON 數據。

a域名去聲明一個方法,b域名去調用這個方法,經過script標籤能夠向不一樣域名提交http請求。

1、原生js實現jsonp

 1.最簡單的一種,客戶端(a域名)的html文件

<!doctype html>
<html lang="en">
<head></head>
<body>
    <script type="text/javascript">
        function jsonpCallback(result) {   
            for(var i in result) {  
                console.log(i+":"+result[i]);//循環輸出result的元素  
            }  
        }  
    </script>
    <script type="text/javascript" src="http://180.167.10.100/update/index.php?callback=jsonpCallback"></script>  
    <!-- 傳遞固定參數的方式 -->
    <!-- <script type="text/javascript" src="http://180.167.10.100/update/index.php?os=Windows&version=3.2.3.660&callback=jsonpCallback"></script> -->  
</body>
</html>

或者

<!doctype html>
<html lang="en">
<head></head>
<body>
    <script type="text/javascript">
        function jsonpCallback(result) {  
            //alert(result);  
            for(var i in result) {  
                console.log(i+":"+result[i]);//循環輸出result的元素  
            }  
        }  
        var JSONP=document.createElement("script");  
        JSONP.type="text/javascript";  
        JSONP.src="http://180.167.10.100/update/index.php?callback=jsonpCallback";  
        document.getElementsByTagName("head")[0].appendChild(JSONP); 
        /*傳遞參數的方式*/
        /*JSONP.src="http://180.167.10.100/update/index.php?os=Windows&version=3.2.3.660&callback=jsonpCallback";*/  
    </script>
</body>
</html>    

服務端(b域名)的php代碼:

<?php    
    //服務端返回JSON數據  
    //$arr=array('a'=>1,'b'=>2,'c'=>3); 
    $arr->IsLatestVersion = False;
    $arr->version = ‘3.3.2.764’;
    $arr->url = "http://172.30.28.18/update/releases/3.2.1.601/Windows/cdos-browser2_3.2.1.601.exe"; 
    $result=json_encode($arr);  
    //動態執行回調函數  
    $callback=$_GET['callback'];  
    echo $callback."($result)";  
?>

 2.在實際的項目中,咱們的jsonp通常不會直接在html文件中實現,由於向服務器獲取數據的時機須要根據咱們項目的實際需求來決定,因此通常須要動態的在咱們所開發的模塊或某個js文件中建立script標籤以及傳遞相關參數(此參數也多是項目過程當中動態生成的),這時咱們能夠在客戶端(a域名)的js文件中以下實現:

// 獲得查詢結果後的回調函數
function jsonpCallback(result) {  
    for(var i in result) {  
        console.log(i+":"+result[i]);//循環輸出result的元素  
    }  
}
function getVersionInfo(){
    var os = "Windows";
    var version = "3.2.3.660";
    var head = document.getElementsByTagName('head')[0];         
    var script = document.createElement('script');//建立script標籤,設置其屬性         
    var url = "http://180.167.10.100/update/index.php?os="+os+"&version="+version+"&callback=jsonpCallback";
    script.type = "text/javascript";                            
    script.setAttribute('src', url);//script.src= url;//提供jsonp服務的url地址
    head.appendChild(script);// 把script標籤加入head,此時調用開始
}
getVersionInfo();    //具體根據實際狀況在合適位置調用便可

可是此時極可能出現報錯「jsonpCallback未定義」,緣由其實很簡單,做爲jsonp的回調函數,jsonpCallback必須是全局函數,而通常因爲項目的模塊化和封裝咱們的函數都是局部函數,此時咱們必須將其全局化,能夠將此回調函數jsonpCallback單拿出來放在html文件中,或者將其經過以下方法綁定到window對象上實現全局化:

(function(){        
    // 獲得查詢結果後的回調函數
    window['jsonpCallback'] = function(data){
        for(var i in result) {  
            console.log(i+":"+result[i]);//循環輸出result的元素  
        }
    };
    function getVersionInfo(){
        var os = "Windows";
        var version = "3.2.3.660";
        var head = document.getElementsByTagName('head')[0];         
        var script = document.createElement('script');//建立script標籤,設置其屬性         
        var url = "http://180.167.10.100/update/index.php?os="+os+"&version="+version+"&callback=jsonpCallback";
        script.type = "text/javascript";                            
        script.setAttribute('src', url);//script.src= url;//提供jsonp服務的url地址
        head.appendChild(script);// 把script標籤加入head,此時調用開始
    }
    getVersionInfo();//具體根據實際狀況在合適位置調用便可
})();

這樣jsonp的原理就很清楚了,首先在客戶端註冊一個callback(名字任意),而後動態建立script標籤經過src引入服務器端的php文件(相似引入js文件的方式),同時將客戶端註冊的callback的名字傳給服務器,php文件載入成功後,服務器先生成咱們須要的 json 數據,而後將其做爲參數傳入咱們在url參數中指定的函數,因此jsonp是須要服務器端的頁面進行相應的配合的。

2、jQuery實現jsonp

jQuery自己就支持JSONP,jQuery封裝的$.ajax中有一個dataType屬性,將該屬性設置成dataType:"jsonp",就能指定按照jsonp方式訪問遠程服務從而實現JSONP跨域了。

注意:雖然jQuery將JSONP封裝在$.ajax中,可是其本質與$.ajax不同。若是設爲dataType: 'jsonp',這個$.ajax方法就和ajax XmlHttpRequest沒什麼關係了,取而代之的則是JSONP協議。

注:jsonp的方式只是針對get請求方式,不支持post請求。這也是Jsonp方式的侷限性

實現原理與用原生js是同樣的,只不過咱們不須要手動的插入script標籤以及定義回調函數,jquery在處理jsonp類型的ajax時(雖然jquery也把jsonp納入了ajax,但其實不是一回事兒),會自動幫咱們生成回調函數並把數據取出來供success屬性方法來調用。

而若是咱們想指定本身的回調函數,或者說服務上規定了固定回調函數名怎麼辦呢?只要以下所示添加一個jsonpCallback的選項,就能夠指定咱們本身的回調方法名myCallback,遠程服務接受callback參數的值就再也不是自動生成的回調名,而是myCallback

jsonp及jsonpCallback的解釋:

更多參數請參考:jQuery.ajax()

客戶端(a域名)的js代碼實現以下:

$(document).ready(function(){
    $.ajax({
        url: "http://180.167.10.100/update/index.php",
        /*url: "http://180.167.10.100/update/index.php?os=Windows&version=3.2.3.660",*//*也能夠直接在url裏面傳遞數據*/
        type: "GET",
        dataType: "jsonp",
jsonp: "callback",//用於指示後臺(php)獲取數據
jsonpCallback: "myCallback",//用於添加本身的回調函數,無此項則回調函數默認爲success
async:
false, data: { 'version': "3.2.3.660", 'os': "Windows", }, timeout:3000, success: function(result) { console.log(result); for(var i in result) { console.log(i+":"+result[i]);//循環輸出result的元素 } }, error: function(xhr) { console.log(xhr); }, }); });

服務器端(b域名)的php代碼實現以下:

<?php
header('Content-Type: text/html; charset=utf-8');
/*獲取客戶端的數據*/
$callback=$_GET['callback'];/*注意跟客戶端指定的jsonp的值一致*/
$os = $_GET['os'];
$version = $_GET['version'];

/*對數據的操做--省略*/
/*對數據的操做--省略*/

/*將數據返回給客戶端*/
$response->IsLatestVersion = False;
$response->version = '3.3.2.764';
$response->url = 'http://180.167.10.100/update/releases/3.3.2.764/Windows/cdos-browser2_update_3.3.2.764.exe'; 
$responseJSON = json_encode($response);
echo $callback."($responseJSON)";
?>

3、$.getJSON方法實現jsonp

$.getJSON()是專門爲ajax獲取json數據而設置的,而且支持"跨域"調用,其語法的格式爲: getJSON(url,[data],[callback])     

實現原理與用原生js是同樣的,一樣咱們不須要手動的插入script標籤以及定義回調函數,jquery會自動生成一個全局函數來替換callback=?中的問號,以後獲取到數據後又會自動銷燬,實際上就是起一個臨時代理函數的做用。$.getJSON方法會自動判斷是否跨域,不跨域的話,就調用普通的ajax方法;跨域的話,則會以異步加載js文件的形式來調用jsonp的回調函數。

客戶端代碼實現以下:

//JQuery JSONP Support  
var url = "http://www.mydomain.com/api/suggest.php?symbol=IBM&callback=?";  
$.getJSON(url, function(result){  
    for(var i in result) {  
    console.log(i+":"+result[i]);//循環輸出result的元素  
    } 
});

2.2.3 ajax和jsonp的區別

一、ajax和jsonp這兩種技術在調用方式上「看起來」很像,目的也同樣,都是請求一個url,而後把服務器返回的數據進行處理,所以jquery和ext等框架都把jsonp做爲ajax的一種形式進行了封裝;

二、但ajax和jsonp其實本質上是不一樣的東西。ajax的核心是經過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加<script>標籤來調用服務器提供的js腳本。

三、因此說,其實ajax與jsonp的區別不在因而否跨域,ajax經過服務端代理同樣能夠實現跨域,jsonp自己也不排斥同域的數據的獲取。

四、還有就是,jsonp是一種方式或者說非強制性協議,如同ajax同樣,它也不必定非要用json格式來傳遞數據,若是你願意,字符串都行,只不過這樣不利於用jsonp提供公開服務。

總而言之,jsonp不是ajax的一個特例,哪怕jquery等巨頭把jsonp封裝進了ajax,也不能改變這一點!

2.2.4 $.get、$.post、$getJSON、$ajax的用法跟區別

首先,$.ajax()是jquery中通用的一個ajax封裝,$.get()和$.post()其實都是$.ajax()的一種,在$.ajax()中有一個type屬性,專門用來指定是get請求仍是post請求的。

$.getJSON()是專門爲ajax從服務器獲取json數據而設置的,而且支持"跨域"調用。jQuery的getJSON()函數,只是設置了JSON參數的ajax()函數的一個簡化版本。這個函數也是能夠跨域使用的,相比get()、post()有必定優點。JSON是一種理想的數據傳輸格式,它可以很好的融合與JavaScript或其餘宿主語言,而且能夠被JS直接使用。使用JSON相比傳統的經過 GET、POST直接發送「裸體」數據,在結構上更爲合理,也更爲安全。
注意:$.getJSON()數據最終仍是經過get方式發送數據出去的,這就決定了,發送的data數據量不能太多,不然形成url太長接收失敗(getJSON方式是不可能有post方式遞交的)。     

具體區別以下:

1.$.ajax()      
$.ajax()是jquery中通用的一個ajax封裝,其語法的格式爲:      
$.ajax(options)      
其中options是一個object類型,它指明瞭本次ajax調用的具體參數,這裏我把最經常使用的幾個參數附上     

$.ajax({      
    url: 'submit.aspx',      
    datatype: "json",      
    type: 'post',      
    success: function (e) {      
        //成功後回調      
        alert("回調函數成功了");      
     },      
    error: function(e){      
        //失敗後回調      
        alert("服務器請求失敗");      
    },      
    beforeSend: function(){      
        //發送請求前調用,能夠放一些"正在加載"之類額話      
        alert("正在加載");           
    }
})

2.$.get      
    $.get()方法使用GET方式來進行異步請求,它的語法結構爲:      
    $.get( url [, data] [, callback] )      
    解釋一下這個函數的各個參數:      
    url:string類型,ajax請求的地址。      
    data:可選參數,object類型,發送至服務器的key/value數據會做爲QueryString附加到請求URL中。      
    callback:可選參數,function類型,當ajax返回成功時自動調用該函數。

$.get("submit.php",{id:'123',name:'小王',},function(data,state){              
    //這裏顯示從服務器返回的數據            
    alert(data);          
    //這裏顯示返回的狀態                
    if(state == 'ok'){      
        alert("返回數據成功");      
    }else{      
        alert("返回數據失敗");      
    }      
});

3.$.post()      
    $.post()方法使用POST方式來進行異步請求,它的語法結構爲:      
    $.post(url,[data],[callback],[type])      
    這個方法和$.get()用法差很少,惟獨多了一個type參數,那麼這裏就只介紹type參數吧,其餘的參考上面$.get()的。      
    type:type爲請求的數據類型,能夠是html,xml,json等類型,若是咱們設置這個參數爲:json,那麼返回的格式則是json格式的,若是沒有設置,就和$.get()返回的格式同樣,都是字符串的。

$.post("submit.php",{id:'123',name:'小明',},function(data,state){              
    //這裏顯示從服務器返回的數據             
    alert(data);        
    //這裏顯示返回的狀態            
    if(state == 'ok'){      
        alert("返回數據成功");      
    }else{      
        alert("返回數據失敗");      
    },
"json");

4.$.getJSON()      
    $.getJSON()是專門爲ajax獲取json數據而設置的,而且支持"跨域"調用,其語法的格式爲:      
    getJSON(url,[data],[callback])      
    url:string類型, 發送請求地址      
    data :可選參數, 待發送 Key/value 參數 ,同get,post類型的data      
    callback :可選參數,載入成功時回調函數,同get,post類型的callback

2.2.4 JSONP的優缺點

JSONP使用起來方便,是目前比較流行的跨域方式,它的優缺點以下:

JSONP的優勢

(1)它不像XMLHttpRequest對象實現的Ajax請求那樣受到同源策略的限制,JSONP能夠跨越同源策略;
(2)它的兼容性更好,在更加古老的瀏覽器中均可以運行,不須要XMLHttpRequest或ActiveX的支持
(3)在請求完畢後能夠經過調用callback的方式回傳結果。將回調方法的權限給了調用方。這個就至關於將controller層和view層終於分開了。我提供的jsonp服務只提供純服務的數據,至於提供服務以 後的頁面渲染和後續view操做都由調用者來本身定義就行了。若是有兩個頁面須要渲染同一份數據,大家只須要有不一樣的渲染邏輯就能夠了,邏輯均可以使用同 一個jsonp服務。

JSONP的缺點:適用範圍過小(只能GET), 有安全風險(返回的代碼會直接執行)
(1)它只支持GET請求而不支持POST等其它類型的HTTP請求
(2)它只支持跨域HTTP請求這種狀況,不能解決不一樣域的兩個頁面之間如何進行JavaScript調用的問題。
(3)jsonp在調用失敗的時候不會返回各類HTTP狀態碼,要肯定 JSONP 請求是否失敗並不容易。雖然 HTML5 給<script>元素新增了一個 onerror事件處理程序,但目前尚未獲得任何瀏覽器支持。爲此,開發人員不得不使用計時器檢測指定時間內是否接收到了響應。
(4)存在安全風險。由於JSONP 是從其餘域(服務端)中加載代碼並直接執行,若是其餘域不安全,極可能會在響應中夾帶一些惡意代碼,因而全部調用這個 jsonp的網站都會存在漏洞,沒法把危險控制在一個域名下,而此時除了徹底放棄 JSONP 調用以外,沒有辦法追究。所以在使用不是你本身運維的 Web 服務時,必定得保證它安全可靠。

 三、解決跨域問題-CORS/XHR2

3.1 概念

爲了改善網絡應用程序,開發人員要求瀏覽器供應商容許跨域請求。

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-Origin Resource Sharing),它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

跨域請求主要用於:

  • 調用XMLHttpRequest或fetchAPI經過跨站點方式訪問資源
  • 網絡字體,例如Bootstrap(經過CSS使用@font-face 跨域調用字體)
  • 經過canvas標籤,繪製圖表和視頻。

HTML5提供的XMLHttpRequest Level2已經實現了跨域訪問以及其餘的一些新功能,CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10。

整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。

3.2 實現

CORS背後的基本思想是使用自定義的HTTP頭部容許瀏覽器和服務器相互瞭解對方,從而決定請求或響應成功與否.

Access-Control-Allow-Origin:指定受權訪問的域
Access-Control-Allow-Methods:受權請求的方法(GET, POST, PUT, DELETE,OPTIONS等)

如在服務器端添加以下代碼便可:
header('Access-Control-Allow-Origin:*');//設置能夠訪問的域,星號表明全部域均可以訪問
header('Access-Control-Allow-Methods:POST,GET');

配合XHR2的IE10如下跨域:
在代碼中js加上一句jQuery.support.cors =true;或者$.support.cors =true; 
而後:設置IE瀏覽器->Internet選項->安全->自定義級別->其餘選項下面的->經過源數據:選擇「啓用」或者「提示」

詳細可參考:

跨域資源共享 CORS 詳解

利用CORS實現跨域請求

CORS——跨域請求那些事兒

CORS 跨域 實現思路及相關解決方案

3.3 CORS 對比 JSONP

都能解決 Ajax直接請求普通文件存在跨域無權限訪問的問題

(1)JSONP只能實現GET請求,而CORS支持全部類型的HTTP請求

(2)使用CORS,開發者可使用普通的XMLHttpRequest發起請求和得到數據,比起JSONP有更好的錯誤處理

(3)JSONP主要被老的瀏覽器支持,它們每每不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS!

四、解決跨域問題-代理

經過在同域名的web服務器端建立一個代理,用本地服務器的後臺調用其餘域的後臺服務,而後把相應結果返回給前端,這樣前端調用同域名服務器的服務和其餘域的服務同樣了。(由後臺實現,瞭解

五、其餘跨域方法

參考:

JavaScript跨域總結與解決辦法

js中幾種實用的跨域方法原理詳解

相關文章
相關標籤/搜索