Fetch 與 XMLHttpRequest
在瀏覽器中,我們常常會遇到需要向服務器發送請求獲取信息的場景,即無需全屏刷新就可以獲取對應信息。以上情景通常被稱為 Ajax 請求或 SPA(單頁應用程序)。
從 1999 年到 2015 年,XMLHttpRequest 是實現要求的唯一方式 。雖然 Ajax 全名是“異步的 JS + XML”,但 XMLHttpRequest 允許細粒度的控制,它可以處理除XML 以外格式的響應,比如文本、二進制、JSON 和 HTML。
從 2015 年開始,瀏覽器實現了 Fetch API,Fetch API 提供了一個獲取資源的接口,對于任何使用過 XMLHttpRequest 的人都能輕松上手,它提供了一種更精簡、更容易、更一致的替代方案。
Fetch使用
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))
fetch() 調用返回一個 ?Promise?,可以通過對 Promise 提供有關結果信息的 Response 對象進行解析獲取想要的內容。
const response = await fetch(url, {
method: 'GET'
})
fetch() 接受兩個參數:
- ?resource 資源路徑?:字符串或 URL 對象
- options 可選選項參數
options 對象可以在 Node 或客戶端代碼中設置屬性,可設置部分屬性如下:
| 屬性 | 值 |
|---|---|
| method | ?GET?/POST/PUT/PATCH/DELETE/HEAD |
| headers | Headers 對象 |
| body | 字符串、FormData、Blob 等 |
| mode | same-origin/no-cors/cors/navigate/websocket |
| credentials | omit/same-origin/include |
| redirect | follow/error/manual |
| referrer | 引用 URL |
| priority | high/low/auto |
| integrity | 子資源完整性哈希URL |
| cache | default/no-store/reload/no-cache/force-cache/only-if-cached |
| signal | 用于取消請求的 AbortSignal 對象 |
其中關于我們常用的請求頭headers設置,可以使用 Headers 對象相關操作對請求和響應中的 HTTP header進行檢查。
// 初始化 headers
const headers = new Headers({
'Content-Type': 'text/plain'
})
// 添加
headers.append('Authorization', 'Bear abc123')
// 添加/更改
headers.set('Content-Type', 'application/json')
// 獲取
const type = headers.get('Content-Type')
// 判斷
if (headers.has('Authorization')) {
// 刪除
headers.delete('Authorization')
}
// 循環
headers.forEach((value, name) => {
console.log(`${name}: ${value}`)
})
// 在 fetch() 中使用
const response = await fetch(url, {
method: 'GET',
headers
})
// response.headers 返回一個 Headers 對象
response.headers.forEach((value, name) => {
console.log(`${name}: ${value}`)
})
fetch響應
當接收到一個 HTTP 錯誤狀態碼時,從 fetch() 返回的 Promise 不會被標記為 reject, 即使響應的 HTTP 狀態碼是 404 或 500。相反,它會將 Promise 狀態標記為 resolve 。
fetch() Promise 只在以下情況下才會返回 reject:
- 發送請求無效,比如資源路徑有誤: fetch('httttps://!invalid\URL/');
- fetch() 請求中止
- 請求出現網絡錯誤,比如連接失敗
那么既然大多數場景下我們會收到 resolve, 那么該如何判斷接口返回是否真正成功呢--就得依賴 fetch 返回的 response 對象進行判斷了。
成功的fetch()調用將返回一個 Response 對象,對象中包含相關狀態及返回數據的信息。Response 對象主要屬性如下:
| 屬性 | 說明 |
|---|---|
| headers | 響應 Headers 對象 |
| ok | 布爾值,若響應成功則為 true |
| redirected | 是否來自重定向 |
| status | HTTP 狀態碼,如 200 表示成功 |
| statusText | HTTP 狀態文本,比如OK對應 200 |
| type | 響應類型:basic、cors等 |
| url | URL |
| body | body 內容 |
| bodyUsed | body 是否讀取 |
Response 對象常用的方法如下所示,他們都返回一個 Promise。
| clone() | 克隆響應 |
|---|---|
| text() | 返回被解析為字符串的Promise |
| json() | 返回被解析為 JSON 的Promise |
| arrayBuffer() | 返回被解析為 ArrayBuffer 的Promise |
| blob() | 返回被解析為 Blob 的Promise |
| formData() | 返回被解析為 FormData 的Promise |
// response 示例
const response = await fetch(url)
// 響應返回 JSON
if (
response.ok &&
response.headers.get('Content-Type') === 'application/json'
) {
// 解析 JSON
const result = await response.json()
console.log(result, 'result')
}
如何中止fetch請求
在實際應用中有以下情況需要中止請求:
- 避免接口請求時間過長仍未得到服務器響應的情況,我們應該設置超時時間,當請求時間大于超時時間未得到響應時及時中止請求
- 避免未得到響應的無效請求占用資源
那么fetch如何中止請求呢?
// 創建 AbortController,1分鐘后超時中止
const controller = new AbortController()
const signal = controller.signal
const timeout = setTimeout(() => controller.abort(), 60000)
try {
const response = await fetch(url, { signal })
clearTimeout(timeout)
console.log(response.ok)
} catch (err) {
// timeout or network error
console.log(err)
}
fetch中使用 AbortController 對象,它將 signal 屬性作為options傳遞給 fetch() 參數, 如果接口在設定時間內沒有返回響應,那么就會觸發取消請求。除此之外,也可根據使用場景通過 controller.abort()手動取消對應請求。