
前端開發(fā)最重要的部分之一是通過發(fā)出HTTP請(qǐng)求與后端進(jìn)行通信,我們有幾種方法可以異步地在Javascript中進(jìn)行API調(diào)用。
幾年前,大多數(shù)應(yīng)用程序都使用Ajax發(fā)送HTTP請(qǐng)求,Ajax代表異步Javascript和XML。但是現(xiàn)在,開發(fā)人員通常會(huì)決定在 .fetch() API和Axios之間進(jìn)行選擇。
在本文中,我想比較這兩種方法,并簡(jiǎn)要介紹一下基本知識(shí)和語法。除此之外,我還將比較在兩種情況下以及在錯(cuò)誤處理中將數(shù)據(jù)轉(zhuǎn)換為JSON格式的過程。我還將討論HTTP攔截和下載進(jìn)度。
開始吧!
Fetch概述和語法
在構(gòu)建Javascript項(xiàng)目時(shí),我們可以使用window對(duì)象,并且它帶有許多可以在項(xiàng)目中使用的出色方法。這些功能之一是Fetch API,它提供了一種簡(jiǎn)單的全局 .fetch()?方法,這是一種從API異步獲取數(shù)據(jù)的邏輯解決方案。
讓我們看一下 .fetch()?方法的語法。
fetch(url)
??.then((res)?=>?
????//?handle?response
??)
??.catch((error)?=>?{
????//?handle?error
??})
在上面的示例中,您可以看到簡(jiǎn)單的獲取GET請(qǐng)求的語法。在 .fetch()?方法中,我們有一個(gè)強(qiáng)制性參數(shù)url,它返回一個(gè)Promise,可以使用Response對(duì)象來解決。
.fetch()?方法的第二個(gè)參數(shù)是選項(xiàng),它是可選的。如果我們不傳遞 options,請(qǐng)求總是GET,它從給定的URL下載內(nèi)容。
在選項(xiàng)參數(shù)里面,我們可以傳遞方法或頭信息,所以如果我們想使用POST方法或其他方法,我們必須使用這個(gè)可選的數(shù)組。
正如我之前提到的,Promise會(huì)返回Response對(duì)象,正因?yàn)槿绱耍覀冃枰褂昧硪粋€(gè)方法來獲取響應(yīng)的主體。有幾種不同的方法可以使用,取決于我們需要的格式:
fetch(url,?{
??method:?'POST',
??headers:?{
????'Content-Type':?'application/json'
??},
??body:?JSON.stringify(data)
});
??.then((response)?=>?response.json())
??.catch((error)?=>?console.log(error))
在上面的代碼示例中,你可以看到簡(jiǎn)單的POST請(qǐng)求,包括 method、header 和 body params。然后我使用 json()?方法將響應(yīng)轉(zhuǎn)換為JSON格式。現(xiàn)在,讓我們仔細(xì)看看axios。
Axios概述和語法
Axios是一個(gè)Javascript庫,用于從Node.js或XMLHttpRequests或?yàn)g覽器發(fā)出HTTP請(qǐng)求。作為一個(gè)現(xiàn)代的庫,它是基于Promise API的。axios 有一些優(yōu)勢(shì),比如對(duì)XSRF的保護(hù)或取消請(qǐng)求。為了能夠使用 axios 庫,我們必須將其安裝并導(dǎo)入到我們的項(xiàng)目中。可以使用CDN,npm或bower安裝 axios。現(xiàn)在,讓我們來看一個(gè)簡(jiǎn)單的GET方法的語法。axios.get(url)
??.then(response?=>?console.log(response));
??.catch((error)?=>?console.log(error));
在上面的代碼中,你可以看到我使用 .get()?方法創(chuàng)建一個(gè)簡(jiǎn)單的GET請(qǐng)求。如果你想在函數(shù)中使用POST方法,那么只需使用 .post()?方法代替,并將請(qǐng)求數(shù)據(jù)作為參數(shù)傳遞即可。當(dāng)我們創(chuàng)建配置對(duì)象時(shí),我們可以定義一堆屬性,最常見的是:作為響應(yīng),axios 返回一個(gè)promise,該promise將與響應(yīng)對(duì)象或錯(cuò)誤對(duì)象一起解析。在響應(yīng)對(duì)象中,具有以下值:- data,這是實(shí)際的響應(yīng)主體
- status,調(diào)用的HTTP狀態(tài),例如200或404
- statusText,以文本消息形式返回的HTTP狀態(tài),例如?ok
- headers,服務(wù)器發(fā)回標(biāo)頭
- request,XMLHttpRequest對(duì)象
現(xiàn)在,讓我們看一下帶有數(shù)據(jù)的POST方法的代碼示例。axios.post({
??'/url',?
??{?name:?'John',?age:?22},
??{?options?}
})
在上面的代碼中,你可以看到 post 方法,我們把config對(duì)象作為param,其中有URL、數(shù)據(jù)和附加選項(xiàng)。我們還可以將config對(duì)象定義為變量,然后像下面的示例一樣將其傳遞給 axios。const?config?=?{
??url:?'http://api.com',
??method:?'POST',
??header:?{
????'Content-Type':?'application/json'
??},
??data:?{
????name:?'John',
????age:?22
??}
}
axios(config);
在這里,你可以看到所有的參數(shù),包括URL、數(shù)據(jù)或方法,都在config對(duì)象中,所以在一個(gè)地方定義所有的東西可能更容易。
如前所述,當(dāng)我們?cè)谑褂?.fetch()?方法的時(shí)候,需要對(duì)響應(yīng)數(shù)據(jù)使用某種方法,當(dāng)我們?cè)诎l(fā)送帶有請(qǐng)求的body時(shí),需要對(duì)數(shù)據(jù)進(jìn)行字符串化。在 axios 中,它是自動(dòng)完成的,所以我們只需在請(qǐng)求中傳遞數(shù)據(jù)或從響應(yīng)中獲取數(shù)據(jù)。它是自動(dòng)字符串化的,所以不需要其他操作。讓我們看看如何從 fetch()?和 axios 獲取數(shù)據(jù)。//?fetch
fetch('url')
??.then((response)?=>?response.json())
??.then((data)?=>?console.log(data))
??.catch((error)?=>?console.log(error))
//?axios
axios.get('url')
??.then((response)?=>?console.log(response))
??.catch((error)?=>?console.log(error))
在上面的例子中,你可以看到,使用 axios 我們沒有額外的一行代碼,在 .fetch()的例子中,我們必須將數(shù)據(jù)轉(zhuǎn)換為JSON格式。在一個(gè)較大的項(xiàng)目中,如果你創(chuàng)建了大量的調(diào)用,那么使用 axios 來避免重復(fù)代碼會(huì)更舒服。
錯(cuò)誤處理
在這一點(diǎn)上,我們還需要給 axios 點(diǎn)贊,因?yàn)樘幚礤e(cuò)誤是非常容易的。如果出現(xiàn)像404這樣的錯(cuò)誤響應(yīng),promise就會(huì)被拒絕并返回一個(gè)錯(cuò)誤,所以我們需要捕獲一個(gè)錯(cuò)誤,我們可以檢查它是什么類型的錯(cuò)誤,就是這樣。讓我們看看代碼示例。axios.get('url')
??.then((response)?=>?console.log(response))
??.catch((error)?=>?{
????if?(error.response)?{
??????//?When?response?status?code?is?out?of?2xx?range?
??????console.log(error.response.data)
??????console.log(error.response.status)
??????console.log(error.response.headers)
????}?else?if?(error.request)?{
??????//?When?no?response?was?recieved?after?request?was?made
??????console.log(error.request)
????}?else?{
??????//?Error
??????console.log(error.message)
????}
??})
在上面的代碼中,當(dāng)響應(yīng)良好時(shí),我返回了數(shù)據(jù),但是如果請(qǐng)求以任何方式失敗,我就能夠檢查 .catch()?部分中的錯(cuò)誤類型并返回正確的消息。對(duì)于 .fetch()?方法,就比較復(fù)雜了。每次我們從 .fetch()?方法中得到響應(yīng)時(shí),我們需要檢查狀態(tài)是否成功,因?yàn)榧词共皇牵覀円矔?huì)得到響應(yīng)。在 .fetch()?的情況下,只有當(dāng)請(qǐng)求沒有完成時(shí),promise才會(huì)被解決。讓我們看一下代碼示例。fetch('url')
??.then((response)?=>?{
????if?(!response.ok)?{
??????throw?Error(response.statusText);
????}
????return?response.json()
??})
??.then((data)?=>?console.log(data))
??.catch((error)?=>?console.log(error))
在這段代碼中,我已經(jīng)在承諾對(duì)象中檢查了代碼的狀態(tài),如果響應(yīng)有狀態(tài) ok,那么我就可以處理并使用 .json()?方法,但如果沒有,我必須在 .then()?里面返回錯(cuò)誤。為了方便和正確的錯(cuò)誤處理,對(duì)于你的項(xiàng)目來說,axios 絕對(duì)會(huì)是一個(gè)更好的解決方案,但如果你正在構(gòu)建一個(gè)只有一兩個(gè)請(qǐng)求的小項(xiàng)目,使用 .fetch()?是可以的,但你需要記住正確處理錯(cuò)誤。
下載進(jìn)度
當(dāng)我們需要下載大量的數(shù)據(jù)時(shí),一種跟蹤進(jìn)度的方法會(huì)很有用,特別是當(dāng)用戶的網(wǎng)絡(luò)速度很慢時(shí)。早期,為了實(shí)現(xiàn)進(jìn)度指標(biāo),開發(fā)者使用了 XMLHttpRequest.onprogress 回調(diào)。在 .fetch()?和 axios 中,有不同的方法來實(shí)現(xiàn)。為了在 .fetch()?中跟蹤下載進(jìn)度,我們可以使用其中一個(gè) response.body 屬性,一個(gè) ReadableStream 對(duì)象。它逐塊提供主體數(shù)據(jù),并允許我們計(jì)算時(shí)間消耗了多少數(shù)據(jù)。在axios中,實(shí)現(xiàn)一個(gè)進(jìn)度指示器也是可能的,而且更容易,因?yàn)榇嬖谝粋€(gè)現(xiàn)成的模塊,可以安裝和實(shí)現(xiàn),它叫做Axios Progress Bar。如果你有大量的大數(shù)據(jù)要下載,你想跟蹤進(jìn)度指標(biāo)的進(jìn)度,你可以用 axios 來管理,更容易更快,但 .fetch()?也提供了這種可能性,只是它需要更多的代碼來開發(fā)同樣的結(jié)果。
HTTP攔截
當(dāng)我們需要檢查或改變我們從應(yīng)用程序到服務(wù)器的HTTP請(qǐng)求時(shí),或者以其他方式,例如,為了驗(yàn)證,HTTP攔截可能是重要的。在 axios 的情況下,HTTP攔截是這個(gè)庫的關(guān)鍵功能之一,這就是為什么我們不需要?jiǎng)?chuàng)建額外的代碼來使用它。讓我們看一下代碼示例,看看我們能做到多么容易。//?請(qǐng)求攔截
axios.interceptors.request.use((config)?=>?{
??console.log('Request?sent');
})
//?響應(yīng)攔截
axios.interceptors.response.use((response)?=>?{
??//?do?an?operation?on?response
??return?response
})
axios.get('url')
??.then((response)?=>?console.log(response))
??.catch((error)?=>?console.log(error))
在代碼中,您可以看到請(qǐng)求攔截和響應(yīng)攔截。在第一種情況下,我創(chuàng)建了一個(gè) console.log,告知發(fā)送請(qǐng)求的情況,在響應(yīng)攔截中,我們可以對(duì)響應(yīng)做任何操作,然后返回。.fetch()?默認(rèn)不提供HTTP攔截功能,我們可以覆蓋 .fetch()?方法,定義發(fā)送請(qǐng)求過程中需要發(fā)生的事情,當(dāng)然,這需要更多的代碼,可能比使用 axios 功能更復(fù)雜。
總結(jié)
在這篇文章中,我比較了用于創(chuàng)建HTTP請(qǐng)求的兩種方法,從簡(jiǎn)單的概述開始,通過語法和一些重要的功能,如下載進(jìn)度或錯(cuò)誤處理。通過比較可以看出,對(duì)于有大量HTTP請(qǐng)求,需要良好的錯(cuò)誤處理或HTTP攔截的應(yīng)用,Axios是一個(gè)更好的解決方案。在小型項(xiàng)目的情況下,只需要幾個(gè)簡(jiǎn)單的API調(diào)用,F(xiàn)etch也是一個(gè)不錯(cuò)的解決方案。在選擇項(xiàng)目的最佳解決方案時(shí),還要注意一個(gè)因素,這是非常重要的。大多數(shù)瀏覽器和Node.js環(huán)境都支持Axios,而現(xiàn)代瀏覽器僅支持Fetch,并且某些版本可能會(huì)與舊版本一起發(fā)布。通過這些知識(shí)的了解,希望大家能夠選擇出最適合自己的方案,也希望大家覺得這個(gè)比較有幫助。
點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開更多互動(dòng)和交流。