什麼是 Fetch API
Fetch API 提供了一個 JavaScript 介面,用於訪問和操縱 HTTP 管道的部分,例如請求和響應。它還提供了一個全域性 fetch()方法,該方法提供了一種簡單,合理的方式來跨網路非同步獲取資源。
為什麼要使用 Fetch
網路非同步獲取資源之前是用XMLHttpRequest
(例如常見的 jquery.ajax(),axios 都是這種)獲取的,Fetch 提供了一個更好的替代方法。現代瀏覽器基本都內建了,不用額外引入,IE 也可以使用 polyfill 等一堆外掛解決,其他瀏覽器開箱即用。
為什麼要封裝 Fetch
-
當接收到一個代表錯誤的 HTTP 狀態碼時,從 fetch()返回的 Promise 不會被標記為 reject, 即使該 HTTP 響應的狀態碼是 404 或 500。相反,它會將 Promise 狀態標記為 resolve (但是會將 resolve 的返回值的 ok 屬性設定為 false ),僅當網路故障時或請求被阻止時,才會標記為 reject。
-
預設情況下,fetch 不會從服務端傳送或接收任何 cookies, 如果站點依賴於使用者 session,則會導致未經認證的請求(要傳送 cookies,必須設定 credentials 選項)。
-
還有最重要的一點,不用每次都寫一堆程式碼。
不瞭解 Fetch 使用方法的這裡提供一下MDN 的教程
簡易程式碼 原始碼使用了 TypeScript 和 async/await
// fetch-config.ts
import Qs from 'qs'
export enum ContentType {
json = 'application/json;charset=UTF-8',
form = 'application/x-www-form-urlencoded; charset=UTF-8'
}
export enum HttpMethod {
get = 'GET',
post = 'POST',
put = 'PUT',
patch = 'PATCH',
delete = 'DELETE'
}
export interface IReqConfig {
body?: any
method?: string
headers?: IHeader
token?: string
'Content-Type'?: string
}
export interface IHeader {
'Content-Type': string
'X-Requested-With': string
token: string
[propName: string]: any
}
export const baseUrl = '/'
const $req = async (url: string, config: IReqConfig) => {
let promise: Response
let contentType: string
if (config['Content-Type'] !== undefined) {
contentType = config['Content-Type']
} else if (config.method === HttpMethod.post) {
contentType = ContentType.form
} else {
contentType = ContentType.json
}
const reqUrl = (baseUrl + url).replace('//', '/')
const headers: Headers = new Headers({
// 如果例項配置沒傳token過來的話,直接使用儲存在sessionStorage的token
// 這裡假設後端直接讀標頭檔案的token欄位,我直接用token當欄位了,Authorization也同理
token: config.token === undefined ? sessionStorage.token : config.token,
'Content-Type': contentType
} as IHeader)
if (!config.method || config.method === HttpMethod.get) {
promise = await fetch(reqUrl, {
headers
})
} else if (config.method === HttpMethod.post) {
promise = await fetch(reqUrl, {
body: Qs.stringify(config.body),
headers,
method: HttpMethod.post
})
} else {
promise = await fetch(reqUrl, {
body: JSON.stringify(config.body),
headers,
method: config.method
})
}
return handleRes(promise)
}
const handleRes = async (res: Response) => {
const parsedRes = await parseRes(res)
// 如果res.ok,則請求成功
if (res.ok) {
return parsedRes
}
// 請求失敗,返回解析之後的失敗的資料
const error = parsedRes
throw error
}
const parseRes = async (res: Response) => {
const contentType = res.headers.get('Content-Type')
// 判定返回的內容型別,做不同的處理
if (contentType) {
if (contentType.indexOf('json') > -1) {
return await res.json()
}
if (contentType.indexOf('text') > -1) {
return await res.text()
}
if (contentType.indexOf('form') > -1) {
return await res.formData()
}
if (contentType.indexOf('video') > -1) {
return await res.blob()
}
}
return await res.text()
}
export default $req
複製程式碼
使用的時候
// test.ts
import $req, { HttpMethod } from './fetch-config'
async function getMethod() {
const getUrl: string = 'XXXX'
try {
const res: any = await $req(getUrl)
} catch(e) {
// 處理異常
}
}
async function postMethod() {
const postUrl: string = 'XXXX'
const reqBody: any = {/* request body */}
try {
const res: any = await $req(postUrl, {
body: reqBody,
method: HttpMethod.post
})
} catch(e) {
// 處理異常
}
}
async function patchMethod() {
const patchUrl: string = 'XXXX'
const reqBody: any = {/* request body */}
try {
const res: any = await $req(patchUrl, {
body: reqBody,
method: HttpMethod.patch
})
} catch(e) {
// 處理異常
}
}
複製程式碼
以上就是 fetch API 的簡單封裝,如果用的 JavaScript 的話,把型別和列舉去掉就好,沒什麼差別