Ajax - 跨域請求

本文為原創作品。歡迎轉載,轉載請注明出處:林東洲的博客 | Lindz Blog

Ajax概念

Ajax全稱為:'Asynchronous Javascript And XML',即異步Javascript和XML,指的是一種創建交互式網頁開發技術。

注意,Ajax是一種技術,它并不是一門編程語言。

簡單說來,傳統的網頁如果需要更新內容,就必須要重新加載整個頁面。

而通過Ajax在后臺與服務器進行少量的數據交換,可以使網頁實現異步更新。這就意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新

例:


Ajax請求

比如我在百度上搜索ajax,其實我并沒有點擊‘百度一下‘按鈕進行提交表單,但是頁面已經向后臺發起ajax請求獲取數據,并將獲取到的數據在頁面上進行局部更新。

Ajax實戰

了解了Ajax的概念之后,接下來就可以學習如何發起Ajax請求了。

在學習Ajax之前首先來創建一個form表單:

<form>
    <label>Name:<input type='text' id="name" name="name"/></label> <br>
    <input type="submit" value="提交" id='submit'>
</form>
<div>Result:<span id="result"></span></div>

表單中有個輸入框和提交按鈕,還有一個用來存儲結果的div。
效果:

Form表單

Ajax對象創建

Ajax核心是 Javascript對象 XMLHttpRequest。在創建Ajax對象前需要對所使用的瀏覽器進行判斷來創建不同的實例。

var request;
if(window.XMLHttpRequest){
    request = new XMLHttpRequest();
}else{
    request = new ActiveXObject('Microsoft.XMLHTTP');
}

通過檢測window對象中是否有XMLHttpRequest屬性來確定瀏覽器是否支持標準的XMLHttpRequest。

注意,請不要用瀏覽器的navigator.userAgent來檢測瀏覽器是否支持某個Javascript特性。因為這個字符串可以偽造,而且一般不會采用通過IE的版本判斷Javascript特性。

當然也可以使用try catch語句來創建XMLHttpRequest對象。

var request = null;
try{
    request = new XMLHttpRequest();
}catch(e){
    try{
        request = new ActiveXObject('Msxml2.XMLHTTP');
    }catch(e){
        request = new ActiveXObject('Microsoft.XMLHTTP');
    }
}

基本上常用的創建Ajax對象的方式就是這兩種,可以選擇封裝在一個函數中。

XMLHttp=new XMLHttpRequest()已經被大多數現代標準瀏覽器所支持。
但為了兼容IE瀏覽器,按微軟的方式:XMLHttp=new ActiveXObject("Msxml2.XMLHTTP") 支持IE6+的版本。
如果捕獲錯誤,則嘗試更老的方法:XMLHttp=new ActiveXObject("Microsoft.XMLHTTP") 支持IE5.5+的版本。

設置回調函數

在創建Ajax請求后,要先設置onreadystatechange回調函數(即在請求數據返回后進行的操作)。在回調函數中通常我們只需通過readyState === 4判斷請求是否完成。如果已完成,再根據status === 200 判斷是否是一個成功的響應。

readyState值:(1.2.3.4.5)

  1. 請求未初始化
  2. 服務器連接已建立
  3. 請求已接收
  4. 請求處理中
  5. 請求已完成,且響應已就緒

code:

request.onreadystatechange = function () {
    if (request.readyState === 4){      
        if (request.status === 200){      
            document.getElementById('result').innerHTML = request.responseText;       
        }
    }
}

發送請求

接下來就是要設置XMLHttpRequest對象中的open()方法,open()方法一共接受三個參數,第一個參數指定是GET還是POST,第二個參數指定URL地址,第三個參數指定是否使用異步發送請求,默認值是true,所以可以不用填寫。

注意:千萬不要把第三個參數設置為false,否則瀏覽器將停止響應,直到Ajax請求完成,如果這個請求耗時10秒,那么10秒內你會發現瀏覽器處于'假死'狀態。

最后調用send()方法才算真正發送請求,GET請求不需要參數,POST請求需要把body部分以字符串或者FormData對象傳進去。

code:

document.getElementById('submit').onclick = function () {
    var url = 'index.php?' +'name=' + document.getElementById('name'); 
    request.open('GET',url,true);
    request.send();
    return false;
}

給提交按鈕綁定一個點擊事件,在點擊的時候將請求數據發送給后臺,return false避免表單提交。

這樣Ajax請求就完成了,已經可以實現不刷新頁面局部刷新。

后臺代碼

這里我使用php來完成實例。

$a[]="Anna";
$a[]="Brittany";
$a[]="Cinderella";
$a[]="Diana";
$a[]="Eva";
$a[]="Fiona";
$a[]="Gunda";
$a[]="Hege";
$a[]="Inga";
$a[]="Johanna";
$a[]="Kitty";
$a[]="Linda";
$a[]="Nina";
$a[]="Ophelia";
$a[]="Petunia";
$a[]="Amanda";
$a[]="Raquel";
$a[]="Cindy";
$a[]="Doris";
$a[]="Eve";
$a[]="Evita";
$a[]="Sunniva";
$a[]="Tove";
$a[]="Unni";
$a[]="Violet";
$a[]="Liza";
$a[]="Elizabeth";
$a[]="Ellen";
$a[]="Wenche";
$a[]="Vicky";

$name = $_GET['name'];
        
if(strlen($name) > 0){
    $result = '';
    for($i = 0; $i < count($a); $i++){
        if(strtolower($name) == strtolower($a[$i])){
            $result = "find the person: $a[$i]";
        }
    }
}
if($result == ''){
    $result = "Can't find the person: $name";
}
echo $result;

這樣前后端就可以跑通了。

測試

測試
測試

安全限制

注意到了上面URL使用的相對路徑,如果將它改成絕對路徑比如:

var url = 'http://127.0.0.1:63342/htdocs/ajax/request.php?name=' + document.getElementById('name').value;

將會報錯,在Chrome的控制臺里,還可以看到錯誤信息。

這是因為瀏覽器的同源策略導致的。默認情況下,JavaScript在發送Ajax請求時,URL的域名必須和當前頁面完全一致。

完全一致的意思是,域名要相同(www.example.comexample.com不同),協議要相同(http和https不同),端口號要相同(默認是:80端口,它和:8080就不同)。有的瀏覽器口子松一點,允許端口不同,大多數瀏覽器都會嚴格遵守這個限制。

跨域請求方法

一、是通過Flash插件發送HTTP請求,這種方式可以繞過瀏覽器的安全限制,但必須安裝Flash,并且跟Flash交互。不過Flash用起來麻煩,而且現在用得也越來越少了。

二、是通過在同源域名下架設一個代理服務器來轉發,JavaScript負責把請求發送到代理服務器:

'/proxy?url=http:/www.example.com'

代理服務器再把結果返回,這樣就遵守了瀏覽器的同源策略。這種方式麻煩之處在于需要服務器端額外做開發。

三、JSONP

即JSON with Padding,是JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數據訪問的問題。

它有個限制,只能用GET請求,并且要求返回JavaScript。這種方式跨域實際上是利用了瀏覽器允許跨域引用JavaScript資源。

即Web頁面上調用Js文件時可以不受跨域限制的影響,不僅如此,凡是擁有'src'這個屬性的標簽都擁有跨域的能力,比如:script, img, iframe標簽。

代碼如下:

var jsonp = document.createElement('script');
jsonp.type = 'text/javascript';
jsonp.src = 'http://www.example.com/remote.js';
document.getElementsByTagName('head')[0].appendChild(jsonp);

四、CORS

Cross-Origin Resource Sharing 跨域資源共享, CORS是一種允許當前域(domain)的資源(比如html/js/web service)被其他域(domain)的腳本請求訪問的機制。

注:如果瀏覽器支持HTML5,那么就可以一勞永逸地使用新的跨域策略:CORS了。

在了解CORS前,先來搞清楚概念:

Origin表示本域,也就是瀏覽器當前頁面的域。當JavaScript向外域(如sina.com)發起請求后,瀏覽器收到響應后,首先檢查Access-Control-Allow-Origin是否包含本域,如果是,則此次跨域請求成功,如果不是,則請求失敗,JavaScript將無法獲取到響應的任何數據。

CORS

假設本域是my.com,外域是sina.com,只要響應頭Access-Control-Allow-Origin為http://my.com,或者是*,本次請求就可以成功。

可見,跨域能否成功,取決于對方服務器是否愿意給你設置一個正確的Access-Control-Allow-Origin,決定權始終在對方手中。

服務器端對于CORS的支持,主要就是通過設置Access-Control-Allow-Origin來進行的,可以添加header頭:

//php
header("Access-Control-Allow-Origin: http://www.example.com");

上面這種跨域請求,稱之為“簡單請求”。簡單請求包括GET、HEAD和POST(POST的Content-Type類型 僅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出現任何自定義頭(例如,X-Custom: 12345),通常能滿足90%的需求。

注:現代瀏覽器一般都是用JSONP或者CORS來完成跨域請求。

CORS與JSONP相比,更為先進、方便和可靠。

  1. JSONP只能實現GET請求,而CORS支持所有類型的HTTP請求。
  2. 使用CORS,開發者可以使用普通的XMLHttpRequest發起請求和獲得數據,比起JSONP有更好的錯誤處理。
  3. JSONP主要被老的瀏覽器支持,它們往往不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容