AJAX 跨域請求常用兩種處理方法

AJAX 跨域請求常用兩種處理方法

--

第一募舟、 使用 跨域資源共享(CORS)

CORS(Cross-Origin Resource Sharing)跨域資源共享薄啥,定義了必須在訪問跨域資源時(shí)梆掸,瀏覽器與服務(wù)器應(yīng)該如何溝通解寝。CORS背后的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通驼仪,從而決定請求或響應(yīng)是應(yīng)該成功還是失敗已脓。

使用方法也很簡單珊楼,在php后端設(shè)置 Access-Control-Allow-Origin 頭即可,如:
復(fù)制代碼

<?php
header("Access-Control-Allow-Origin: *");
//header("Access-Control-Allow-Origin: 我的域或ip");

// 接收數(shù)據(jù)
// $jsoncallback = $_GET["jsoncallback"];

// 構(gòu)造數(shù)據(jù)
for($i=1; $i<=5; $i++){ 
    $names[] = array("name" => "name" + $i);
}

// $data = $jsoncallback . "(" . json_encode($names) . ")";

$data = json_encode($names);
echo $data;

?>

第二度液、使用jsonp

Asynchronous JavaScript and XML (Ajax ) 是驅(qū)動新一代 Web 站點(diǎn)(流行術(shù)語為 Web 2.0 站點(diǎn))的關(guān)鍵技術(shù)厕宗。Ajax 允許在不干擾 Web 應(yīng)用程序的顯示和行為的情況下在后臺進(jìn)行數(shù)據(jù)檢索。使用 XMLHttpRequest 函數(shù)獲取數(shù)據(jù)堕担,它是一種 API已慢,允許客戶端 JavaScript 通過 HTTP 連接到遠(yuǎn)程服務(wù)器。Ajax 也是許多 mashup 的驅(qū)動力霹购,它可將來自多個(gè)地方的內(nèi)容集成為單一 Web 應(yīng)用程序佑惠。

不過,由于受到瀏覽器的限制厕鹃,該方法不允許跨域通信兢仰。如果嘗試從不同的域請求數(shù)據(jù)乍丈,會出現(xiàn)安全錯(cuò)誤剂碴。如果能控制數(shù) 據(jù)駐留的遠(yuǎn)程服務(wù)器并且每個(gè)請求都前往同一域,就可以避免這些安全錯(cuò)誤轻专。但是忆矛,如果僅停留在自己的服務(wù)器上,Web 應(yīng)用程序還有什么用處呢请垛?如果需要從多個(gè)第三方服務(wù)器收集數(shù)據(jù)時(shí)催训,又該怎么辦?

理解同源策略限制

同源策略阻止從一個(gè)域上加載的腳本獲取或操作另一個(gè)域上的文檔屬性宗收。也就是說漫拭,受到請求的 URL 的域必須與當(dāng)前 Web 頁面的域相同。這意味著瀏覽器隔離來自不同源的內(nèi)容混稽,以防止它們之間的操作采驻。這個(gè)瀏覽器策略很舊审胚,從 Netscape Navigator 2.0 版本開始就存在。

克服該限制的一個(gè)相對簡單的方法是讓 Web 頁面向它源自的 Web 服務(wù)器請求數(shù)據(jù)礼旅,并且讓 Web 服務(wù)器像代理一樣將請求轉(zhuǎn)發(fā)給真正的第三方服務(wù)器膳叨。盡管該技術(shù)獲得了普遍使用,但它是不可伸縮的痘系。另一種方式是使用框架要素在當(dāng)前 Web 頁面中創(chuàng)建新區(qū)域菲嘴,并且使用 GET 請求獲取任何第三方資源。不過汰翠,獲取資源后龄坪,框架中的內(nèi)容會受到同源策略的限制。

克服該限制更理想方法是在 Web 頁面中插入動態(tài)腳本元素奴璃,該頁面源指向其他域中的服務(wù) URL 并且在自身腳本中獲取數(shù)據(jù)悉默。腳本加載時(shí)它開始執(zhí)行。該方法是可行的苟穆,因?yàn)橥床呗圆蛔柚箘討B(tài)腳本插入抄课,并且將腳本看作是從提供 Web 頁面的域上加載的。但如果該腳本嘗試從另一個(gè)域上加載文檔雳旅,就不會成功跟磨。幸運(yùn)的是,通過添加 JavaScript Object Notation (JSON) 可以改進(jìn)該技術(shù)攒盈。

1抵拘、什么是JSONP?

要了解JSONP型豁,不得不提一下JSON僵蛛,那么什么是JSON ?

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.

JSONP(JSON with Padding)是一個(gè)非官方的協(xié)議迎变,它允許在服務(wù)器端集成Script tags返回至客戶端充尉,通過javascript callback的形式實(shí)現(xiàn)跨域訪問(這僅僅是JSONP簡單的實(shí)現(xiàn)形式)。

2衣形、JSONP有什么用驼侠?

由于同源策略的限制,XmlHttpRequest只允許請求當(dāng)前源(域名谆吴、協(xié)議倒源、端口)的資源,為了實(shí)現(xiàn)跨域請求句狼,可以通過script標(biāo)簽實(shí)現(xiàn)跨域請求笋熬,然后在服務(wù)端輸出JSON數(shù)據(jù)并執(zhí)行回調(diào)函數(shù),從而解決了跨域的數(shù)據(jù)請求腻菇。

3胳螟、如何使用JSONP箭阶?

下邊這一DEMO實(shí)際上是JSONP的簡單表現(xiàn)形式煎饼,在客戶端聲明回調(diào)函數(shù)之后,客戶端通過script標(biāo)簽向服務(wù)器跨域請求數(shù)據(jù),然后服務(wù)端返回相應(yīng)的數(shù)據(jù)并動態(tài)執(zhí)行回調(diào)函數(shù)黔衡。

HTML代碼 (任一 ):

Html代碼 收藏代碼

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
<script type="text/javascript">  
    function jsonpCallback(result) {  
        //alert(result);  
        for(var i in result) {  
            alert(i+":"+result[i]);//循環(huán)輸出a:1,b:2,etc.  
        }  
    }  
    var JSONP=document.createElement("script");  
    JSONP.type="text/javascript";  
    JSONP.src="http://crossdomain.com/services.php?callback=jsonpCallback";  
    document.getElementsByTagName("head")[0].appendChild(JSONP);  
</script>  

或者

Html代碼 收藏代碼

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
<script type="text/javascript">  
    function jsonpCallback(result) {  
        alert(result.a);  
        alert(result.b);  
        alert(result.c);  
        for(var i in result) {  
            alert(i+":"+result[i]);//循環(huán)輸出a:1,b:2,etc.  
        }  
    }  
</script>  
<script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonpCallback"></script>  

JavaScript的鏈接则果,必須在function的下面蓄坏。

服務(wù)端PHP代碼 (services.php):

Php代碼 收藏代碼

<?php  
  
//服務(wù)端返回JSON數(shù)據(jù)  
$arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);  
$result=json_encode($arr);  
//echo $_GET['callback'].'("Hello,World!")';  
//echo $_GET['callback']."($result)";  
//動態(tài)執(zhí)行回調(diào)函數(shù)  
$callback=$_GET['callback'];  
echo $callback."($result)";  

如果將上述JS客戶端代碼用jQuery的方法來實(shí)現(xiàn)董习,也非常簡單。

$.getJSON
$.ajax
$.get

客戶端JS代碼在jQuery中的實(shí)現(xiàn)方式1:

Js代碼 收藏代碼

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.getJSON("http://crossdomain.com/services.php?callback=?",  
    function(result) {  
        for(var i in result) {  
            alert(i+":"+result[i]);//循環(huán)輸出a:1,b:2,etc.  
        }  
    });  
</script>  

客戶端JS代碼在jQuery中的實(shí)現(xiàn)方式2:

Js代碼 收藏代碼

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.ajax({  
        url:"http://crossdomain.com/services.php",  
        dataType:'jsonp',  
        data:'',  
        jsonp:'callback',  
        success:function(result) {  
            for(var i in result) {  
                alert(i+":"+result[i]);//循環(huán)輸出a:1,b:2,etc.  
            }  
        },  
        timeout:3000  
    });  
</script>  

客戶端JS代碼在jQuery中的實(shí)現(xiàn)方式3:

Js代碼 收藏代碼

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.get('http://crossdomain.com/services.php?callback=?', {name: encodeURIComponent('tester')}, function (json) { for(var i in json) alert(i+":"+json[i]); }, 'jsonp');  
</script>  

其中 jsonCallback 是客戶端注冊的周拐,獲取 跨域服務(wù)器 上的json數(shù)據(jù) 后铡俐,回調(diào)的函數(shù)。
http://crossdomain.com/services.php?callback=jsonpCallback
這個(gè) url 是跨域服務(wù) 器取 json 數(shù)據(jù)的接口妥粟,參數(shù)為回調(diào)函數(shù)的名字审丘,返回的格式為

Js代碼 收藏代碼

jsonpCallback({msg:'this is json data'})  

Jsonp原理:
首先在客戶端注冊一個(gè)callback, 然后把callback的名字傳給服務(wù)器。

此時(shí)勾给,服務(wù)器先生成 json 數(shù)據(jù)滩报。
然后以 javascript 語法的方式,生成一個(gè)function , function 名字就是傳遞上來的參數(shù) jsonp.

最后將 json 數(shù)據(jù)直接以入?yún)⒌姆绞讲ゼ保胖玫?function 中脓钾,這樣就生成了一段 js 語法的文檔,返回給客戶端桩警。

客戶端瀏覽器可训,解析script標(biāo)簽,并執(zhí)行返回的 javascript 文檔捶枢,此時(shí)數(shù)據(jù)作為參數(shù)握截,傳入到了客戶端預(yù)先定義好的 callback 函數(shù)里.(動態(tài)執(zhí)行回調(diào)函數(shù))

使用JSON的優(yōu)點(diǎn)在于:

比XML輕了很多,沒有那么多冗余的東西烂叔。
JSON也是具有很好的可讀性的谨胞,但是通常返回的都是壓縮過后的。不像XML這樣的瀏覽器可以直接顯示长已,瀏覽器對于JSON的格式化的顯示就需要借助一些插件了畜眨。
在JavaScript中處理JSON很簡單昼牛。
其他語言例如PHP對于JSON的支持也不錯(cuò)术瓮。

JSON也有一些劣勢:

JSON在服務(wù)端語言的支持不像XML那么廣泛,不過JSON.org上提供很多語言的庫贰健。
如果你使用eval()來解析的話胞四,會容易出現(xiàn)安全問題。

盡管如此伶椿,JSON的優(yōu)點(diǎn)還是很明顯的辜伟。他是Ajax數(shù)據(jù)交互的很理想的數(shù)據(jù)格式氓侧。

ps:

JSONP 是構(gòu)建 mashup 的強(qiáng)大技術(shù),但不幸的是导狡,它并不是所有跨域通信需求的萬靈藥约巷。它有一些缺陷,在提交開發(fā)資源之前必須認(rèn)真考慮它們旱捧。

第一独郎,也是最重要的一點(diǎn),沒有關(guān)于 JSONP 調(diào)用的錯(cuò)誤處理枚赡。如果動態(tài)腳本插入有效氓癌,就執(zhí)行調(diào)用;如果無效贫橙,就靜默失敗贪婉。失敗是沒有任何提示的。例如卢肃,不能從服務(wù)器捕捉到 404 錯(cuò)誤疲迂,也不能取消或重新開始請求。不過莫湘,等待一段時(shí)間還沒有響應(yīng)的話鬼譬,就不用理它了。(未來的 jQuery 版本可能有終止 JSONP 請求的特性)逊脯。

JSONP 的另一個(gè)主要缺陷是被不信任的服務(wù)使用時(shí)會很危險(xiǎn)优质。因?yàn)?JSONP 服務(wù)返回打包在函數(shù)調(diào)用中的 JSON 響應(yīng),而函數(shù)調(diào)用是由瀏覽器執(zhí)行的军洼,這使宿主 Web 應(yīng)用程序更容易受到各類攻擊巩螃。如果打算使用 JSONP 服務(wù),了解它能造成的威脅非常重要匕争。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末避乏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子甘桑,更是在濱河造成了極大的恐慌拍皮,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跑杭,死亡現(xiàn)場離奇詭異铆帽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)德谅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門爹橱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窄做,你說我怎么就攤上這事愧驱∥考迹” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵组砚,是天一觀的道長吻商。 經(jīng)常有香客問我,道長糟红,這世上最難降的妖魔是什么手报? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮改化,結(jié)果婚禮上掩蛤,老公的妹妹穿的比我還像新娘。我一直安慰自己陈肛,他們只是感情好揍鸟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著句旱,像睡著了一般阳藻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谈撒,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天腥泥,我揣著相機(jī)與錄音,去河邊找鬼啃匿。 笑死蛔外,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溯乒。 我是一名探鬼主播夹厌,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裆悄!你這毒婦竟也來了矛纹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤光稼,失蹤者是張志新(化名)和其女友劉穎或南,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾君,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡采够,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腻贰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吁恍。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扒秸,死狀恐怖播演,靈堂內(nèi)的尸體忽然破棺而出冀瓦,到底是詐尸還是另有隱情,我是刑警寧澤写烤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布翼闽,位于F島的核電站,受9級特大地震影響洲炊,放射性物質(zhì)發(fā)生泄漏感局。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一暂衡、第九天 我趴在偏房一處隱蔽的房頂上張望询微。 院中可真熱鬧,春花似錦狂巢、人聲如沸撑毛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藻雌。三九已至,卻和暖如春斩个,著一層夾襖步出監(jiān)牢的瞬間胯杭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工受啥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留做个,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓滚局,卻偏偏與公主長得像叁温,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子核畴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容