前端必備HTTP技能之XMLHttpRequest對(duì)象詳解

XMLHttpRequest(XHR)是一個(gè)API對(duì)象,其中的方法可以用來(lái)在瀏覽器和服務(wù)器端傳輸數(shù)據(jù)。這個(gè)對(duì)象是瀏覽器的js環(huán)境提供的。從XHR獲取數(shù)據(jù)的目的是為了持續(xù)修改一個(gè)加載過(guò)的頁(yè)面,XHR是Ajax設(shè)計(jì)的底層概念。XHR使用的協(xié)議不同于HTTP,不僅可以使用XML格式的數(shù)據(jù),也支持JSON,HTML或者純文本。

WHATWG組織負(fù)責(zé)維護(hù)一個(gè)動(dòng)態(tài)的XHR標(biāo)準(zhǔn)文檔。W3C基于WHATWG標(biāo)準(zhǔn)創(chuàng)建了一個(gè)固定的規(guī)范。

歷史

XMLHttpRequest對(duì)象背后的概念最開始是被微軟Outlook Web Access工作組為Microsoft Exchange Server 2000提出的。一個(gè)IXMLHTTPRequest接口被開發(fā)出來(lái),第二代的MSXML庫(kù)實(shí)現(xiàn)了這個(gè)概念。1999年的發(fā)布的IE5使用了第二代的MSXML庫(kù),通過(guò)ActiveX訪問(wèn)IXMLHTTPRequest接口,這個(gè)接口在MSXML中通過(guò)XMLHTTP包裝。

IE5,IE6沒有在他們的腳本語(yǔ)言中定義XMLHttpRequest對(duì)象的標(biāo)識(shí)符,當(dāng)時(shí)IE5,IE6發(fā)布時(shí),XMLHttpRequest標(biāo)識(shí)符本身還不是一個(gè)標(biāo)準(zhǔn)。如果XMLHttpRequest標(biāo)識(shí)符不存在,通過(guò)對(duì)象檢測(cè)可以獲得向后兼容性。微軟在2006年發(fā)布的IE7時(shí),定義了XMLHttpRequest對(duì)象標(biāo)識(shí)符。

Mozilla項(xiàng)目組為Gecko布局引擎開發(fā)實(shí)現(xiàn)的接口稱為nsIXMLHttpRequest。這個(gè)接口被建模成盡可能的接近微軟的IXMLHTTPRequest接口。Mozilla通過(guò)js對(duì)象為這個(gè)接口創(chuàng)建了一個(gè)包裝器稱為XMLHttpRequest。XMLHttpRequest首次可用是在2000年12月6號(hào)發(fā)布的Gecko 0.6版本中,但是還不是全功能版本直到2002年6月5號(hào)發(fā)布的1.0版本的Gecko。XMLHttpRequest對(duì)象在其他主要的web客戶端中變成了一個(gè)事實(shí)標(biāo)準(zhǔn),在2004年2月發(fā)布得Safari 1.2版本,2005年4月發(fā)布的KonquerorOpera8.0版本,2005年9月發(fā)布的iCab 3.0b352版本中都實(shí)現(xiàn)了這個(gè)對(duì)象。

隨著跨瀏覽器JS庫(kù)(例如jQuery)流行,開發(fā)者再調(diào)用XMLHttpRequest功能時(shí)不用再直接接觸底層API。

標(biāo)準(zhǔn)

W3C在2006年4月5號(hào)發(fā)布了一個(gè)關(guān)于XMLHttpRequest對(duì)象的工作草案規(guī)范,起草人是Opera的Anne van Kesteren和W3C的Dean Jackson。它的目標(biāo)是“基于現(xiàn)有的實(shí)現(xiàn),文檔化一個(gè)最小的可以互相協(xié)作的特性,以便web開發(fā)者可以不用編寫特定平臺(tái)代碼來(lái)使用這些特性”。

W3C在2008年2月25號(hào)又發(fā)布了另一個(gè)關(guān)于XMLHttpRequest對(duì)象的工作草案,稱為"XMLHttpRequest Level 2"。這個(gè)版本的XMLHttpRequest包括了XMLHttpRequest對(duì)象的擴(kuò)展功能,例如事件處理,支持跨域請(qǐng)求,支持處理字節(jié)流。2011年底,這個(gè)規(guī)范被遺棄了,其中的內(nèi)容收錄在原始的規(guī)范中。

在2012年底,WHATWG接管了這個(gè)事情,并且用Web IDL定義了一個(gè)標(biāo)準(zhǔn)。W3C目前的草案就是基于WHATWG標(biāo)準(zhǔn)創(chuàng)建的。

HTTP請(qǐng)求

下面的章節(jié)展示了符合W3C工作草案標(biāo)準(zhǔn)的用戶代理如何使用XMLHttpRequest對(duì)象功能發(fā)起http請(qǐng)求。因?yàn)閃3C關(guān)于XMLHttpRequest對(duì)象的標(biāo)準(zhǔn)仍然是一個(gè)草案,所以用戶代理可能沒有完全實(shí)現(xiàn)草案規(guī)定的功能,也就是下面的這些是有可能變化的。當(dāng)使用XMLHttpRequest對(duì)象的腳本跨用戶代理使用時(shí),要考慮下這種影響。本文將試著列出主要的用戶代理之間不一致的地方。

open方法

XMLHttpRequest對(duì)象的HTTP和HTTPS請(qǐng)求必須通過(guò)opent方法初始化。這個(gè)方法必須在實(shí)際發(fā)送請(qǐng)求之前調(diào)用,以用來(lái)驗(yàn)證請(qǐng)求方法,URL以及用戶信息。這個(gè)方法不能確保URL存在或者用戶信息必須正確。初始化請(qǐng)求可以接受5個(gè)參數(shù),

open( Method, URL, Asynchronous, UserName, Password )

第一個(gè)參數(shù)是一個(gè)字符串值標(biāo)識(shí)HTTP的請(qǐng)求方法。請(qǐng)求方法必須是用戶代理支持的方法以及W3C的XMLHttpRequest對(duì)象草案規(guī)定的方法,如下:

  • GET (IE7+,Mozilla 1+)
  • POST (IE7+,Mozilla 1+)
  • HEAD (IE7+)
  • PUT
  • DELETE
  • OPTIONS (IE7+)

然而請(qǐng)求方法并不限于以上列出的這些。W3C草案聲明瀏覽器可以自行決定支持的請(qǐng)求方法。

第二個(gè)參數(shù)也是一個(gè)字符串值,標(biāo)示請(qǐng)求的URL。W3C推薦當(dāng)有跨域請(qǐng)求時(shí),瀏覽器應(yīng)該報(bào)個(gè)錯(cuò)誤。

第三個(gè)參數(shù)是一個(gè)布爾值類型,標(biāo)示請(qǐng)求是否是異步的,在W3C草案中并不是一個(gè)必須參數(shù)。如果沒有提供,符合W3C規(guī)范的用戶代理應(yīng)該默認(rèn)為true。異步請(qǐng)求("true")不會(huì)等待服務(wù)器響應(yīng)在繼續(xù)執(zhí)行其他腳本之前,可以調(diào)用XMLHttpRequest對(duì)象的onreadystatechange事件監(jiān)聽器來(lái)獲取請(qǐng)求的不同狀態(tài)。一個(gè)同步的請(qǐng)求("false")會(huì)阻塞js執(zhí)行直到請(qǐng)求完成,這時(shí)就沒必要調(diào)用onreadystatechange事件監(jiān)聽器。

第四個(gè)和第五個(gè)參數(shù)分別是用戶名和密碼。這些參數(shù)是服務(wù)端為了驗(yàn)證請(qǐng)求使用的。

    var xmlhttp;

    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", filepath , false);
        xmlhttp.send(null);
    }
sendRequestHeader方法

在成功初始化請(qǐng)求之后,XMLHttpRequest對(duì)象的setRequestHeader方法可以用來(lái)設(shè)置請(qǐng)求頭。

setRequestHeader( Name, Value )

第一個(gè)參數(shù)是header的字符串名稱,第二個(gè)參數(shù)是字符串值。如果請(qǐng)求需要多個(gè)header,這個(gè)方法就要被調(diào)用多次。這個(gè)方法附加的請(qǐng)求頭,在下次open方法調(diào)用時(shí)會(huì)被清空。

send方法

XMLHttpRequest對(duì)象的send方法用來(lái)發(fā)送請(qǐng)求,這個(gè)方法接收一個(gè)參數(shù),這個(gè)參數(shù)就是要發(fā)送的內(nèi)容。

send(Data)

如果不需要發(fā)送內(nèi)容,這個(gè)參數(shù)可以省略。W3C草案聲明這個(gè)參數(shù)可以是任意類型的值只要能被js轉(zhuǎn)成字符串,除了DOM對(duì)象。如果用戶代理無(wú)法序列化這個(gè)參數(shù),這個(gè)參數(shù)會(huì)被忽略。Firefox3.0.x以及之前版本在send方法沒傳參數(shù)時(shí)會(huì)拋出異常。

如果參數(shù)是DOM對(duì)象,用戶代理應(yīng)該確保文檔已經(jīng)被轉(zhuǎn)成XML格式,通過(guò)文檔對(duì)象的inputEncoding屬性編碼。如果請(qǐng)求頭的Content-Type還沒有通過(guò)setRequestHeader方法設(shè)置,用戶代理應(yīng)該自動(dòng)的增加一個(gè)值"application/xml;charset=charset",其中的charset應(yīng)該是用來(lái)編碼文檔的編碼格式。

如果用戶代理被配置成使用代理服務(wù)器,XMLHttpRequest對(duì)象應(yīng)該適當(dāng)修改請(qǐng)求連接代理而不是源服務(wù)器,發(fā)送Proxy-Authorization頭配置。

onreadystatechange事件監(jiān)聽器

如果XMLHttpRequest對(duì)象的send方法第三個(gè)參數(shù)是true,也就是發(fā)送了異步請(qǐng)求,onreadystatechange事件監(jiān)聽器將自動(dòng)在XMLHttpRequest對(duì)象的readyState屬性改變時(shí)被觸發(fā)。

狀態(tài)改變過(guò)程如下:

  • 當(dāng)open方法被成功調(diào)用,readyState屬性被置為1(OPEND)
  • 當(dāng)send方法被調(diào)用,成功接收到HTTP響應(yīng)頭,readyState屬性被置為2(HEADERS_RECEIVED)
  • 一旦HTTP響應(yīng)內(nèi)容開始加載,readyState屬性被置為3(LOADING)
  • 一旦HTTP響應(yīng)內(nèi)容結(jié)束加載,readyState屬性被置為4(DONE)

當(dāng)監(jiān)聽器被定義之后,每次狀態(tài)改變時(shí)都會(huì)觸發(fā)。為了檢測(cè)狀態(tài)1和狀態(tài)2,監(jiān)聽器必須在open方法調(diào)用前調(diào)用。open方法必須在send方法調(diào)用前調(diào)用。

    var request = new XMLHttpRequest();
    request.onreadystatechange = function () {
        var DONE = this.DONE || 4;
        if (this.readyState === DONE){
            alert(this.readyState);
        }
    };
    request.open('GET', 'somepage.xml', true);
    request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
    request.send(null);
abort方法

如果XMLHttpRequest對(duì)象的readyState屬性還沒有變成4,這個(gè)方法可以終止請(qǐng)求。這個(gè)方法可以確保異步請(qǐng)求中的回調(diào)不被執(zhí)行。

abort()

一些AJAX庫(kù)使用abort方法來(lái)取消潛在重復(fù)請(qǐng)求以及無(wú)序請(qǐng)求。

HTTP響應(yīng)

當(dāng)成功調(diào)用XMLHttpRequest對(duì)象的send方法之后,如果服務(wù)端響應(yīng)式格式正確的XML,并且已經(jīng)把Content-Type頭設(shè)置成用戶代理支持的XML類型,XMLHttpRequest對(duì)象的responseXML屬性將會(huì)包含一個(gè)DOM文檔對(duì)象。另外一個(gè)屬性responseText將會(huì)包含服務(wù)端返回的文本類型,而不管它是否被理解為XML。

跨域請(qǐng)求

早起的web開發(fā)中,通過(guò)使用js在一個(gè)web站點(diǎn)和另一個(gè)不安全的站點(diǎn)交換信息的方式,很容易突破用戶的安全防線。因此所有的現(xiàn)代瀏覽器實(shí)現(xiàn)了一個(gè)同源策略來(lái)阻止類似攻擊,例如跨站腳本。XMLHttpRequest數(shù)據(jù)也受這種安全策略支配,但是有時(shí)web開發(fā)想有意的規(guī)避這種限制。因?yàn)橛袝r(shí)需要合法使用子域,例如在foo.example.com域上的頁(yè)面發(fā)送XMLHttpRequest請(qǐng)求獲取bar.example.com域上的數(shù)據(jù)通常會(huì)失敗。

存在各種規(guī)避這種安全策略的方法,例如可以使用JSONP,跨域資源共享(CORS),或者flash,silverlight插件。跨域XMLHttpRequest請(qǐng)求在W3C的XMLHttpRequest Level 2規(guī)范中有提及。IE10+才支持CORS。IE8,IE9提供類似功能的XDomainRequest API。

CORS協(xié)議也有幾點(diǎn)限制,支持兩種模式。簡(jiǎn)單模式不允許設(shè)置自定義頭并且忽略cookie,只支持HEAD,GET,POST請(qǐng)求方法,其中POST方法只允許"text/plain","application/x-www-urlencoded","multipart/form-data"的MIME類型,最初支持的只有"text/plain"類型。另一個(gè)模式檢測(cè)何時(shí)請(qǐng)求復(fù)雜特性之一,然后給服務(wù)端發(fā)送一個(gè)請(qǐng)求確認(rèn)來(lái)協(xié)商特性。

做好前端開發(fā)必須對(duì)HTTP的相關(guān)知識(shí)有所了解,所以我創(chuàng)建了一個(gè)專題前端必備HTTP技能專門收集前端相關(guān)的HTTP知識(shí),歡迎關(guān)注,投稿。


PS:本文翻譯自維基百科,原文地址https://en.wikipedia.org/wiki/XMLHttpRequest

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,582評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,801評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,223評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,442評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,976評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,800評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,996評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,233評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,702評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

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

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 11,056評(píng)論 6 13
  • 本文詳細(xì)介紹了 XMLHttpRequest 相關(guān)知識(shí),涉及內(nèi)容: AJAX、XMLHTTP、XMLHttpReq...
    semlinker閱讀 13,700評(píng)論 2 18
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,785評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,721評(píng)論 18 399
  • 翻手機(jī)圖片翻出了一張考哥的截圖,忍不住少女心又泛濫了一下。 曾經(jīng)有很長(zhǎng)一段時(shí)間里,我熱衷收?qǐng)D,除去手繪練習(xí)素材,其...
    禿濎閱讀 292評(píng)論 0 0