JS 中的網路請求 AJAX, Fetch, WebSocket
AJAX 是 Asynchronous JavaScript And XML 的簡稱,它可以讓頁面在不重新整理的情況下從伺服器獲取資料。
XMLHttpRequest
瀏覽器使用XMLHttpRequest
物件於伺服器通訊,它可以使用JSON,XML,HTML和text等格式傳送和接收資料。
低版本 IE 瀏覽器沒有XMLHttpRequest
物件,但是它可以使用ActiveXObject
物件代替。
if (window.XMLHttpRequest) { // IE7+ XHR = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE 6 XHR = new ActiveXObject("Microsoft.XMLHTTP"); } 複製程式碼
建立 XHR 例項過後就可以監聽該例項的狀態改變事件onreadystatechange
,它會在 XHR 例項的readyState
的值改變時觸發回撥函式。
XHR.onreadystatechange = function () { } 複製程式碼
然後我們就可以使用open
方法初始化一個請求和send
方法傳送 HTTP 請求。
XHR.open('GET', 'http://q.com') // open 方法一共有 5 個引數,method, url, async, user, password 後三個可選。 // async 表示這次是否非同步請求,預設是 true XHR.send() // send 方法接受一個可選引數 請求主體。 // 引數可以是 FormData, FormData, ArrayBuffer, Document, 序列化字串 複製程式碼
如果是post
方法,就要在send
之前設定請求頭的Content-Type
。
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') // 它接受兩個引數 header 和 value 複製程式碼
然後我們就要處理伺服器返回的資料,回到onreadystatechange
函式。它監聽readyState
屬性的變化,而它一共有 5 個值。
我們還需要關心status
屬性它也是隻讀屬性,它是這次響應中的 HTTP 數字狀態碼。在請求之前和 XMLHttpRequest 出錯時它為0
。
responseText
屬性是實際的資料,它是字串,如果相應是 JSON 格式,需要用 JSON 的 parse 處理。
XHR.onreadystatechange = function () { if (XHR.readyState === 4 && XHR.status === 200) { console.log(JSON.parse(XHR.responseText)) } } 複製程式碼
如果伺服器返回的是 XML, 我們可以用responseXML
屬性獲得資料。
// 如果已指明,responseType 必須是空字串或 "docuemnt" XHR.responseType = 'document'; // overrideMimeType() 用來強制解析 response 為 XML XHR.overrideMimeType('text/xml'); // -------------- var root = XHR.responseXML.getElementsByTagName('root').item(0) 複製程式碼
responseType
屬性是一個列舉型別的屬性,返回響應資料的型別。
withCredentials
屬性是一個Boolean型別,它指示了是否該使用類似cookies,authorization headers(頭部授權)或者TLS客戶端證書這一類資格證書來建立一個跨站點訪問控制請求。
(在IE中,超時屬性可能只能在呼叫 open() 方法之後且在呼叫 send() 方法之前設定)
abort
方法用來終止請求
getAllResponseHeaders
方法返回所有的響應頭
getResponseHeader(name)
方法返回包含指定頭文字的字串
XMLHttpRequset 2
XMLHttpRequset 2 增加了一些新功能。比如能傳送FormData
。
超時時間
timeout
屬性是超時時間,單位毫秒。當超時發生時他會觸發ontimeout
回撥函式。
xhr.open('GET', '/server') xhr.timeout = 2000 xhr.ontimeout = function (e) {} xhr.send(null); 複製程式碼
還有 6 個進度事件。
loadstart progress error abort load loadend
有load
事件就不用readystatechange
事件和讀取readyState
屬性。
xhr.addEventListener("progress", updateProgress, false); xhr.addEventListener("load", transferComplete, false); xhr.addEventListener("error", transferFailed, false); xhr.addEventListener("abort", transferCanceled, false); function updateProgress(event) { if (event.lengthComputable) { console.log(`${event.position} / ${event.totalSize}`) } } 複製程式碼
其中progress
的事件物件多了三個屬性。
lengthComputable position totalSize
跨域
同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。
當前網址(http://news.a.com)和請求網址
https://news.a.com http://news.a.com:8080 http://home.a.com
時就不是同源。
為了使 ajax 可以從不同的網址獲取資料。
我們可以使用跨域資源共享(CORS)來解決問題。
在傳送請求時會有個Origin
頭表示請求頁面的源資訊,
如果伺服器返回的Access-Control-Allow-Origin
中有相同的源資訊或是*
那麼就可以跨域請求資訊,請求和響應都不包含cookie
。
CORS通過Preflighted Requests
透明伺服器驗證機制支援使用自定義頭部、get和post之外的方法,不同型別的主題內容。
這種請求已OPTIONS方法傳送,下面是它傳送的頭資訊:
Origin
源
Access-Control-Request-Method
請求自身使用的方法
Access-Control-Request-Headers
自定義頭部資訊,用逗號分隔
傳送請求後,伺服器來決定是否允許,伺服器會發送如下資訊與瀏覽器溝通:
Access-Control-Allow-Origin
允許的源
Access-Control-Allow-Methods
允許的方法,逗號分隔
Access-Control-Allow-Headers
允許的頭部,逗號分隔
Access-Control-Allow-Max-Age
Preflight請求快取的時間(秒)
預設情況下跨域不提供cookie、HTTP認證、SSL證明,通過withCredentials
屬性設定為true
可以指定某個請求因該傳送憑據。
伺服器如果接收請求會返回Access-Control-Allow-Credentials
為true
的頭資訊。
還有一種方法是使用JSONP
。
jsonp
方法主要是建立script
標籤來獲得資料,一般通過請求後面跟?callback=fn
回掉函式來獲取資料。
Fetch
Fetch 是網路請求的一個更好的替代方法。相比於 XMLHttpRequest,Fetch 寫法更簡單,功能更強大。
fetch('http://a.com') .then(function(response) { if (response.ok) { return response.json(); } throw new Error('err') }) .then(function(myJson) { console.log(myJson); }) .catch(err => { console.log(err) }) 複製程式碼
fetch 函式接受兩個引數,返回一個 Promise 物件。
第一個引數是 URL 或 Request 物件。第二個引數是可選一個配置項物件。
{ method: 'GET', // 請求方法 headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, // 頭資訊 body: JSON.stringify({data: 1}), // 請求的 body 資訊,Blob, FormData 等 mode: 'cors', // 請求的模式,cors、 no-cors 或 same-origin credentials: 'include', // omit、same-origin 或 include。為了在當前域名內自動傳送 cookie, 必須提供這個選項 cache: 'no-cache', // default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached redirect: 'follow', // 可用的 redirect 模式: follow (自動重定向), error (如果產生重定向將自動終止並且丟擲一個錯誤), 或者 manual (手動處理重定向). referrer: 'no-referrer', // no-referrer、client或一個 URL。預設是 client。 referrerPolicy: 'no-referrer', // 指定 referer HTTP頭 integrity: 'sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=', // 包括請求的subresource integrity 值 } 複製程式碼
then 的回撥函式接受一個 Response 物件。Response 實現了 Body(代表響應/請求的正文,允許你宣告其內容型別是什麼以及應該如何處理。)
它有 9 個屬性。
type url useFinalURL status ok edirected statusText headers bodyUsed
8 個方法
clone error redirect(url, status)
Body(都返回一個 Promise 例項)
arrayBuffer blob formData json text
WebSocket
WebSockets 是一種先進的技術。它可以在使用者的瀏覽器和伺服器之間開啟雙工、雙向通訊會話。
WebSocket 建構函式,接受兩個引數,url 和 protocols(可選)。
url 以ws://
或wss://
(加密)開頭
protocols 是 單協議字串或者包含協議字串的陣列。這些字串用於指定子協議,這樣單個伺服器可以實現多個WebSocket子協議(例如,您可能希望一臺伺服器能夠根據指定的協議處理不同型別的互動)protocol)。如果不指定協議字串,則假定為空字串。
var s = new WebSocket('ws://www.a.com/s.php') // 必須傳入絕對URL,可以是任何網站 s.readyState // 0 建立連線 1 已經建立 2 正在關閉 3 連線已關閉或者沒有連結成功 s.send('hello') // 傳送的資料必須是純文字 s.onopen = function (){ console.log('成功建立連線時觸發') } s.onerror = function () { console.log('發生錯誤,連線不能持續時') } s.onmessage = function (event) { // 當接收到訊息時 console.log(event.data) // 資料是純字元 } s.close() // 關閉連線 s.onclose = function (event) { /* * event.wasClean 是否明確的關閉 * event.code 伺服器返回的數值狀態碼 * event.reason 字串,伺服器返回的訊息 */ console.log('連線關閉時') } 複製程式碼
一共有 10 個屬性
binaryType bufferedAmount extensions onclose onmessage onopen protocol readyState url
2 個方法
-
close(code, reason)
數字狀態碼 可選 預設 1005和一個可選的類可讀的字串,它解釋了連線關閉的原因。 -
send(data)
向伺服器傳送資料(ArrayBuffer,Blob等)