JS 中的網絡請求 AJAX, Fetch, WebSocket

AJAX 是 Asynchronous JavaScript And XML 的簡稱,它可讓頁面在不刷新的狀況下從服務器獲取數據。javascript

XMLHttpRequest

瀏覽器使用XMLHttpRequest對象於服務器通訊,它可使用JSON,XML,HTML和text等格式發送和接收數據。php

低版本 IE 瀏覽器沒有XMLHttpRequest對象,可是它可使用ActiveXObject對象代替。java

if (window.XMLHttpRequest) { // IE7+
    XHR = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 6
    XHR = new ActiveXObject("Microsoft.XMLHTTP");
}
複製代碼

建立 XHR 實例事後就能夠監聽該實例的狀態改變事件onreadystatechange,它會在 XHR 實例的readyState的值改變時觸發回調函數。web

XHR.onreadystatechange = function () { }
複製代碼

而後咱們就可使用open方法初始化一個請求和send方法發送 HTTP 請求。ajax

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-Typejson

httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

// 它接受兩個參數 header 和 value
複製代碼

而後咱們就要處理服務器返回的數據,回到onreadystatechange函數。它監聽readyState屬性的變化,而它一共有 5 個值。跨域

  1. 0 表示 請求還未初始化,還沒有調用 open() 方法。
  2. 1 表示 已創建服務器連接,open() 方法已經被調用。
  3. 2 表示 請求已接受,send() 方法已經被調用,而且頭部和狀態已經可得到。
  4. 3 表示 正在處理請求,下載中; responseText 屬性已經包含部分數據。
  5. 4 表示 完成,下載操做已完成。

咱們還須要關心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 個進度事件。

  1. loadstart 在收到響應的第一個字節觸發
  2. progress 在接收期間不斷觸發
  3. error 發生錯誤
  4. abort 調用abort方法而終止
  5. load 接收到完整數據
  6. loadend 在通訊完成或abort error load事件後觸發

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的事件對象多了三個屬性。

  1. lengthComputable 布爾值 表示進度信息是否可用
  2. position 已經接收到的字節數
  3. totalSize 根據Content-Length預期的字節數

跨域

同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。

當前網址(http://news.a.com)和請求網址

  1. https://news.a.com 不一樣協議
  2. http://news.a.com:8080 不一樣端口
  3. 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-Credentialstrue的頭信息。

還有一種方法是使用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 個屬性。

  1. type 只讀 包含Response的類型 (例如, basic, cors)
  2. url 只讀 包含Response的URL
  3. useFinalURL 包含了一個布爾值來標示這是不是該Response的最終URL
  4. status 只讀 包含Response的狀態碼
  5. ok 只讀 包含了一個布爾值來標示該Response成功(狀態碼200-299)
  6. edirected 只讀 表示該Response是否來自一個重定向,若是是的話,它的URL列表將會有多個
  7. statusText 只讀 包含了與該Response狀態碼一致的狀態信息
  8. headers 只讀 包含此Response所關聯的Headers 對象
  9. bodyUsed Body 只讀 包含了一個布爾值來標示該Response是否讀取過Body

8 個方法

  1. clone 建立一個Response對象的克隆
  2. error 返回一個綁定了網絡錯誤的新的Response對象
  3. redirect(url, status) 用另外一個URL建立一個新的 response

Body(都返回一個 Promise 實例)

  1. arrayBuffer 接受一個 Response 流, 並等待其讀取完成. 並 resolve 一個 ArrayBuffer 對象
  2. blob blob()方法使用一個 Response 流,並將其讀取完成
  3. formData 將 Response 對象中的所承載的數據流讀取並封裝成爲一個對象
  4. json 使用一個 Response 流,並將其讀取完成。解析結果是將文本體解析爲 JSON
  5. text 提供了一個可供讀取的"返回流", 它返回一個包含USVString對象,編碼爲UTF-8

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 個屬性

  1. binaryType 返回websocket鏈接所傳輸二進制數據的類型(blob, arraybuffer)
  2. bufferedAmount 只讀 返回已經被send()方法放入隊列中但尚未被髮送到網絡中的數據的字節數。一旦隊列中的全部數據被髮送至網絡,則該屬性值將被重置爲0。可是,若在發送過程當中鏈接被關閉,則屬性值不會重置爲0。
  3. extensions 只讀 返回服務器選擇的擴展名。這當前只是空字符串或鏈接協商的擴展列表
  4. onclose 用於指定鏈接失敗後的回調函數
  5. onmessage 用於指定當從服務器接受到信息時的回調函數
  6. onopen 用於指定鏈接成功後的回調函數
  7. protocol 只讀 服務器選擇的下屬協議
  8. readyState 只讀 當前的連接狀態
  9. url 只讀 WebSocket 的絕對路徑

2 個方法

  1. close(code, reason) 數字狀態碼 可選 默認 1005和一個可選的類可讀的字符串,它解釋了鏈接關閉的緣由。
  2. send(data) 向服務器發送數據(ArrayBuffer,Blob等)
相關文章
相關標籤/搜索