XHR简介
在XHR誕生前,網(wǎng)頁要獲取客戶端和服務(wù)器的任何狀態(tài)更新,都需要刷新一次,在XHR誕生后就可以完全通過JS代碼異步實(shí)現(xiàn)這一過程。XHR的誕生也使最初的網(wǎng)頁制作轉(zhuǎn)換為開發(fā)交互應(yīng)用,拉開了WEB2.0的序幕。?
XHR是一種瀏覽器API,極大簡(jiǎn)化了異步通信的過程,開發(fā)者并不需要關(guān)注底層的實(shí)現(xiàn),因?yàn)闉g覽器會(huì)為我們完成這些工作,如連接管理、協(xié)議協(xié)商、HTTP請(qǐng)求格式化等等。最初版本的XHR能力非常有限,只支持文本傳輸,處理上傳能力也不足,對(duì)于跨域請(qǐng)求也不支持。為解決這些問題,W3C于2008年發(fā)布了“XMLHttpRequest Level2”草案,新增了如下功能:
- 支持請(qǐng)求超時(shí);
- 支持傳輸二進(jìn)制和文本數(shù)據(jù);
- 支持重寫媒體類型和編碼響應(yīng);
- 支持監(jiān)控每個(gè)請(qǐng)求的進(jìn)度事件;
- 支持有效的文件上傳;
- 支持安全的跨來源請(qǐng)求。
2011年,W3C將“XMLHttpRequest Level2”規(guī)范與最初的“XMLHttpRequest”規(guī)范合并,所有XHR2新增的功能也都并入了原來的XHR API中,接口不變,功能增強(qiáng)。
1.XHR簡(jiǎn)介
XMLHttpRequest 對(duì)象提供了對(duì) HTTP 協(xié)議的完全的訪問,包括做出 POST 和 HEAD 請(qǐng)求以及普通的 GET 請(qǐng)求的能力。XMLHttpRequest 可以同步或異步地返回 Web 服務(wù)器的響應(yīng),并且能夠以文本或者一個(gè) DOM 文檔的形式返回內(nèi)容。XHR接口強(qiáng)制要求每個(gè)請(qǐng)求都具備嚴(yán)格的HTTP語義–應(yīng)用提供數(shù)據(jù)和URL,瀏覽器格式化請(qǐng)求并管理每個(gè)連接的完整生命周期,所以XHR僅僅允許應(yīng)用自定義一些HTTP首部,但更多的首部是不能自己設(shè)定的,如:
- Accept-Charset, Accept-Encoding, Access-Control-*
- Host, Upgrade, Connection, Referer, Origin
- Cookie, Sec-, Proxy-, 及其他首部
瀏覽器會(huì)拒絕絕對(duì)不安全的首部重寫,以保證應(yīng)用不能假扮用戶代理、用戶或請(qǐng)求來源,如Origin由瀏覽器自動(dòng)設(shè)置,Access-Control-Allow-Origin由服務(wù)器設(shè)置,如果接受該請(qǐng)求,不包含該字段即可,瀏覽器發(fā)出的請(qǐng)求將作廢。
- CORS請(qǐng)求會(huì)省略cookie和HTTP認(rèn)證等用戶憑據(jù);
- 客戶端被限制只能發(fā)送“簡(jiǎn)單的跨域請(qǐng)求”,包括只能使用GET POSD HEAD三種方式,只能訪問通過XHR發(fā)送并讀取的HTTP首部。
如果想要啟用cookie和HTTP認(rèn)證,客戶端必須在發(fā)送請(qǐng)求時(shí)通過XHR對(duì)象發(fā)送額外的屬性(withCredentials),而服務(wù)器也需要以Access-Control-Allow-Credentials響應(yīng),表示允許應(yīng)用發(fā)送隱私數(shù)據(jù)。同樣,如果客戶需要寫入或讀取自定義HTTP標(biāo)頭或想要使用“非簡(jiǎn)單的方法”的請(qǐng)求,那么它必須首先通過發(fā)出一個(gè)預(yù)備請(qǐng)求,以獲取第三方服務(wù)器的許可,如下所示:
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // Preflight request OPTIONS /resource.js HTTP/1.1 Host: thirdparty.com Origin: http://example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: My-Custom-Header ... ? // Preflight response HTTP/1.1 200 OK Access-Control-Allow-Origin: http://example.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: My-Custom-Header ... ? (actual HTTP request) |
W3C CORS規(guī)范定義的什么時(shí)候必須使用預(yù)備請(qǐng)求,“簡(jiǎn)單”的請(qǐng)求可以跳過它,但也有各種各樣場(chǎng)景需要使用預(yù)備請(qǐng)求,這就添加一次往返網(wǎng)絡(luò)延遲。可喜的是,一旦預(yù)備請(qǐng)求完成,它可以由客戶端緩存,以避免在后續(xù)請(qǐng)求進(jìn)行相同的驗(yàn)證。?
在XHR中,可以通過responseType-設(shè)置改變響應(yīng)類型,如下所示:
- “” 字符串(默認(rèn)值)
- “arraybuffer” ArrayBuffer
- “blob” Blob
- “document” Document
- “json” JavaScript 對(duì)象,解析自服務(wù)器傳遞回來的JSON 字符串。
- “text” 字符串
2.數(shù)據(jù)傳輸
2.1.數(shù)據(jù)請(qǐng)求:
下面是通過XHR獲取一張圖片,并顯示到網(wǎng)頁上的示例:
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var?xhr =?new?XMLHttpRequest(); ? xhr.addEventListener("progress", updateProgress,?false); xhr.addEventListener("load", transferComplete,?false); xhr.addEventListener("error", transferFailed,?false); xhr.addEventListener("abort", transferCanceled,?false); ? xhr.open('GET',?'/images/photo.webp'); xhr.responseType =?'blob'; xhr.onload =?function() { ??if?(this.status == 200) { ????var?img = document.createElement('img'); ????img.src = window.URL.createObjectURL(this.response); ????img.onload =?function() { ????????window.URL.revokeObjectURL(this.src); ????} ????document.body.appendChild(img); ??} }; ? xhr.send(); |
2.2.數(shù)據(jù)上傳
上傳相關(guān)事件在 XMLHttpRequest.upload 對(duì)象上被觸發(fā),像下面這樣,向服務(wù)器發(fā)送一個(gè)formdata格式數(shù)據(jù):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var?formData =?new?FormData(); formData.append('id', 123456); formData.append('topic',?'performance'); ? var?xhr =?new?XMLHttpRequest(); ? xhr.upload.addEventListener("progress", updateProgress); xhr.upload.addEventListener("load", transferComplete); xhr.upload.addEventListener("error", transferFailed); xhr.upload.addEventListener("abort", transferCanceled); ? xhr.open('POST',?'/upload'); xhr.onload =?function() { ... }; xhr.send(formData); |
2.3.數(shù)據(jù)分片上傳:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | var?blob = ...; ? const BYTES_PER_CHUNK = 1024 * 1024; const SIZE = blob.size; ? var?start = 0; var?end = BYTES_PER_CHUNK; ? while(start < SIZE) { ??var?xhr =?new?XMLHttpRequest(); ??xhr.open('POST',?'/upload'); ??xhr.onload =?function() { ... }; ? ??xhr.setRequestHeader('Content-Range', start+'-'+end+'/'+SIZE); ??xhr.send(blob.slice(start, end)); ? ??start = end; ??end = start + BYTES_PER_CHUNK; } |
注意:progress 事件在使用 file: 協(xié)議的情況下是無效的。
數(shù)據(jù)冰冷的,但我們要讓數(shù)據(jù)溫暖起來,改變我們的生活!
總結(jié)
- 上一篇: 微星强袭GE66游戏本直降5000:i7
- 下一篇: 对标国产宝马X5!蔚来全新ES7发布:4