前端必備HTTP技能之XMLHttpRequest對象詳解

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

WHATWG組織負責維護一個動態的XHR標準文檔。W3C基于WHATWG標準創建了一個固定的規范。

歷史

XMLHttpRequest對象背后的概念最開始是被微軟Outlook Web Access工作組為Microsoft Exchange Server 2000提出的。一個IXMLHTTPRequest接口被開發出來,第二代的MSXML庫實現了這個概念。1999年的發布的IE5使用了第二代的MSXML庫,通過ActiveX訪問IXMLHTTPRequest接口,這個接口在MSXML中通過XMLHTTP包裝。

IE5,IE6沒有在他們的腳本語言中定義XMLHttpRequest對象的標識符,當時IE5,IE6發布時,XMLHttpRequest標識符本身還不是一個標準。如果XMLHttpRequest標識符不存在,通過對象檢測可以獲得向后兼容性。微軟在2006年發布的IE7時,定義了XMLHttpRequest對象標識符。

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

隨著跨瀏覽器JS庫(例如jQuery)流行,開發者再調用XMLHttpRequest功能時不用再直接接觸底層API。

標準

W3C在2006年4月5號發布了一個關于XMLHttpRequest對象的工作草案規范,起草人是Opera的Anne van Kesteren和W3C的Dean Jackson。它的目標是“基于現有的實現,文檔化一個最小的可以互相協作的特性,以便web開發者可以不用編寫特定平臺代碼來使用這些特性”。

W3C在2008年2月25號又發布了另一個關于XMLHttpRequest對象的工作草案,稱為"XMLHttpRequest Level 2"。這個版本的XMLHttpRequest包括了XMLHttpRequest對象的擴展功能,例如事件處理,支持跨域請求,支持處理字節流。2011年底,這個規范被遺棄了,其中的內容收錄在原始的規范中。

在2012年底,WHATWG接管了這個事情,并且用Web IDL定義了一個標準。W3C目前的草案就是基于WHATWG標準創建的。

HTTP請求

下面的章節展示了符合W3C工作草案標準的用戶代理如何使用XMLHttpRequest對象功能發起http請求。因為W3C關于XMLHttpRequest對象的標準仍然是一個草案,所以用戶代理可能沒有完全實現草案規定的功能,也就是下面的這些是有可能變化的。當使用XMLHttpRequest對象的腳本跨用戶代理使用時,要考慮下這種影響。本文將試著列出主要的用戶代理之間不一致的地方。

open方法

XMLHttpRequest對象的HTTP和HTTPS請求必須通過opent方法初始化。這個方法必須在實際發送請求之前調用,以用來驗證請求方法,URL以及用戶信息。這個方法不能確保URL存在或者用戶信息必須正確。初始化請求可以接受5個參數,

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

第一個參數是一個字符串值標識HTTP的請求方法。請求方法必須是用戶代理支持的方法以及W3C的XMLHttpRequest對象草案規定的方法,如下:

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

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

第二個參數也是一個字符串值,標示請求的URL。W3C推薦當有跨域請求時,瀏覽器應該報個錯誤。

第三個參數是一個布爾值類型,標示請求是否是異步的,在W3C草案中并不是一個必須參數。如果沒有提供,符合W3C規范的用戶代理應該默認為true。異步請求("true")不會等待服務器響應在繼續執行其他腳本之前,可以調用XMLHttpRequest對象的onreadystatechange事件監聽器來獲取請求的不同狀態。一個同步的請求("false")會阻塞js執行直到請求完成,這時就沒必要調用onreadystatechange事件監聽器。

第四個和第五個參數分別是用戶名和密碼。這些參數是服務端為了驗證請求使用的。

    var xmlhttp;

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

在成功初始化請求之后,XMLHttpRequest對象的setRequestHeader方法可以用來設置請求頭。

setRequestHeader( Name, Value )

第一個參數是header的字符串名稱,第二個參數是字符串值。如果請求需要多個header,這個方法就要被調用多次。這個方法附加的請求頭,在下次open方法調用時會被清空。

send方法

XMLHttpRequest對象的send方法用來發送請求,這個方法接收一個參數,這個參數就是要發送的內容。

send(Data)

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

如果參數是DOM對象,用戶代理應該確保文檔已經被轉成XML格式,通過文檔對象的inputEncoding屬性編碼。如果請求頭的Content-Type還沒有通過setRequestHeader方法設置,用戶代理應該自動的增加一個值"application/xml;charset=charset",其中的charset應該是用來編碼文檔的編碼格式。

如果用戶代理被配置成使用代理服務器,XMLHttpRequest對象應該適當修改請求連接代理而不是源服務器,發送Proxy-Authorization頭配置。

onreadystatechange事件監聽器

如果XMLHttpRequest對象的send方法第三個參數是true,也就是發送了異步請求,onreadystatechange事件監聽器將自動在XMLHttpRequest對象的readyState屬性改變時被觸發。

狀態改變過程如下:

  • open方法被成功調用,readyState屬性被置為1(OPEND)
  • send方法被調用,成功接收到HTTP響應頭,readyState屬性被置為2(HEADERS_RECEIVED)
  • 一旦HTTP響應內容開始加載,readyState屬性被置為3(LOADING)
  • 一旦HTTP響應內容結束加載,readyState屬性被置為4(DONE)

當監聽器被定義之后,每次狀態改變時都會觸發。為了檢測狀態1和狀態2,監聽器必須在open方法調用前調用。open方法必須在send方法調用前調用。

    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對象的readyState屬性還沒有變成4,這個方法可以終止請求。這個方法可以確保異步請求中的回調不被執行。

abort()

一些AJAX庫使用abort方法來取消潛在重復請求以及無序請求。

HTTP響應

當成功調用XMLHttpRequest對象的send方法之后,如果服務端響應式格式正確的XML,并且已經把Content-Type頭設置成用戶代理支持的XML類型,XMLHttpRequest對象的responseXML屬性將會包含一個DOM文檔對象。另外一個屬性responseText將會包含服務端返回的文本類型,而不管它是否被理解為XML。

跨域請求

早起的web開發中,通過使用js在一個web站點和另一個不安全的站點交換信息的方式,很容易突破用戶的安全防線。因此所有的現代瀏覽器實現了一個同源策略來阻止類似攻擊,例如跨站腳本。XMLHttpRequest數據也受這種安全策略支配,但是有時web開發想有意的規避這種限制。因為有時需要合法使用子域,例如在foo.example.com域上的頁面發送XMLHttpRequest請求獲取bar.example.com域上的數據通常會失敗。

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

CORS協議也有幾點限制,支持兩種模式。簡單模式不允許設置自定義頭并且忽略cookie,只支持HEAD,GET,POST請求方法,其中POST方法只允許"text/plain","application/x-www-urlencoded","multipart/form-data"的MIME類型,最初支持的只有"text/plain"類型。另一個模式檢測何時請求復雜特性之一,然后給服務端發送一個請求確認來協商特性。

做好前端開發必須對HTTP的相關知識有所了解,所以我創建了一個專題前端必備HTTP技能專門收集前端相關的HTTP知識,歡迎關注,投稿。


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

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

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,054評論 6 13
  • 本文詳細介紹了 XMLHttpRequest 相關知識,涉及內容: AJAX、XMLHTTP、XMLHttpReq...
    semlinker閱讀 13,700評論 2 18
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,719評論 18 399
  • 翻手機圖片翻出了一張考哥的截圖,忍不住少女心又泛濫了一下。 曾經有很長一段時間里,我熱衷收圖,除去手繪練習素材,其...
    禿濎閱讀 292評論 0 0