axios的兩種方式,post傳參但不賦值,Axios 或 fetch():你應該使用哪個?
2019 年 9 月 18 日· 5 分鐘閱讀
在我最近的文章“如何像(xiang)專(zhuan)業(ye)人士一(yi)樣(yang)使用 Axios 發出 HTTP 請求”中(zhong),我討(tao)論了使用 Axios 庫的(de)(de)(de)好(hao)處。盡管如此(ci),重(zhong)要的(de)(de)(de)是承認(ren) Axios 并不總是一個理想的(de)(de)(de)解決方(fang)案,有(you)時有(you)發出(chu) HTTP 請求的(de)(de)(de)更好(hao)選擇。
毫無疑問,一些開發人員更喜歡 Axios 而不是內置 API,因為它易于使用采用。但許多人高估了對這樣一個庫的需求。的fetch() API是完全能夠再現(xian) Axios 的關鍵特性,并且它具有(you)附加(jia)的在所有(you)現(xian)代(dai)瀏覽器中(zhong)都可(ke)以使用的優勢(shi)。
在本文中,我們將比較fetch()和(he) Axios,看(kan)看(kan)它們是如(ru)何(he)使用的(de)執行不同的(de)任務。希望在文章(zhang)的(de)最后,你會對這兩個(ge) API有一個(ge)更(geng)好(hao)的(de)了解。
基本語法
在(zai)我(wo)們深入研究 Axios 更高級的(de)功能之前,讓我(wo)們先(xian)比較一下它(ta)的(de)基本功能。
fetch() 的語法。以下是使用 Axios 發送POST請求的(de)方法URL 的(de)自(zi)定義標頭。Axios 會(hui)自(zi)動將數(shu)據(ju)轉換為 JSON,因此(ci)不必(bi)自(zi)己轉換。
// axiosconst options = { url: '//localhost/test.htm', method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8' }, data: { a: 10, b: 20 } }; axios(options) .then(response => { console.log(response.status); });
現在將此代碼與fetch()版本進行比較,后者產(chan)生相同的(de)結果(guo)
// fetch()const url = '//localhost/test.htm';const options = { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8' }, body: JSON.stringify({ a: 10, b: 20 }) }; fetch(url, options) .then(response => { console.log(response.status); });
請注意:要發送數據,fetch()使用 body 屬性,而 Axios 使用data property。fetch() 中的數據是字符串化的URL 作為參數傳遞給fetch()。然而,在(zai) Axios 中(zhong),URL 是在(zai)option對象中(zhong)設置。
向后兼容
Axios 的主要賣點之一是其廣泛的瀏覽器支持。甚至舊IE11 等瀏覽器可以毫無問題地運行 Axios。另一方面,fetch(),僅支持 Chrome 42+、Firefox 39+、Edge 14+ 和 Safari 10.1+。
如果您使用 Axios 的唯一原因是向后兼容,那么您實際上并沒有需要一個 HTTP 庫。相反,你可以使用fetch()polyfill 來在不支持fetch() 的(de)網(wang)絡瀏覽器上實現類似的(de)功(gong)能(neng)。
要開始(shi)使用(yong) fetch polyfill,請通過 npm 命令安裝它。
npm install whatwg-fetch --save
然后你可以提出(chu)這(zhe)樣的請求:
import 'whatwg-fetch'window.fetch(...)
請記住,您可能還需要(yao)在(zai)一些舊的瀏覽器。
響應超時
在 Axios 中設置超時的簡單性是一些開發人員的原因之一。在Axios中,您可以使用可選的超時屬性,config 對(dui)象設(she)置請求中止前的毫(hao)秒數。例如:
axios({ method: 'post', url: '/login', timeout: 4000, // 4 seconds timeout data: { firstName: 'David', lastName: 'Pollock' } }).then(response => {/* handle the response */}).catch(error => console.error('timeout exceeded'))
fetch()通過AbortController接口提供類似的功能。不(bu)過,它不(bu)像 Axios 版本那(nei)么簡(jian)單
const controller = new AbortController();const options = { method: 'POST', signal: controller.signal, body: JSON.stringify({ firstName: 'David', lastName: 'Pollock' }) }; const promise = fetch('/login', options);const timeoutId = setTimeout(() => controller.abort(), 4000); promise .then(response => {/* handle the response */}) .catch(error => console.error('timeout exceeded'));
在這里,我們創建了一個AbortController使用對象
AbortController.AbortController()構造函數,它允許我們稍后中止請求。singal是AbortController的只讀屬性,提供表示與請求通信或中止它。如果服務器沒有響應不到四秒,調用controller.abort(),操作為終止。
自動 JSON 數據轉換
前面我們說過,Axios 發送請求時會自動對數據進行字符串化(盡管您可以覆蓋默認行為并定義不同的轉換機制)。但是,在使用fetch()時,您必須手動這樣(yang)做。相(xiang)比:
// axiosaxios.get('//api.github.com/orgs/axios') .then(response => { console.log(response.data); }, error => { console.log(error); });// fetch()fetch('//api.github.com/orgs/axios') .then(response => response.json()) // one extra step .then(data => { console.log(data) }) .catch(error => console.error(error));
數據的自動轉換是一個很好的功能,但同樣,你并非不能用fetch()做。
HTTP攔截器
Axios 的(de)關鍵特性之一是它能夠(gou)攔(lan)截 HTTP 請求(qiu)。HTTP當您(nin)需要檢查或更改(gai) HTTP 請求(qiu)時,攔(lan)截器(qi)(qi)會派(pai)上用場。從您(nin)的(de)應用程序到服務器(qi)(qi),反(fan)之亦然(例如,日志記錄、身份驗證、等等。)。使用攔(lan)截器(qi)(qi),您(nin)不(bu)必為每(mei)個 HTTP 編寫(xie)單獨的(de)代碼要求(qiu)。
以下是在 Axios 中聲明(ming)請求攔截器的方法(fa)
axios.interceptors.request.use(config => { // log a message before any HTTP request is sent console.log('Request was sent'); return config; });// sent a GET requestaxios.get('//api.github.com/users/sideshowbarker') .then(response => { console.log(response.data); });
在這段代碼中,
axios.interceptors.request.use()方法用于定義一個在發送 HTTP 請求之前運行的代碼。默認情況下,fetch()不提(ti)供攔截(jie)請求的方法,但并(bing)不難想出(chu)一個(ge)解決方法。您可(ke)以覆蓋全局 fetch 方法并(bing)定義你自己的攔截(jie)器,像(xiang)這樣:
fetch = (originalFetch => { return (...arguments) => { const result = originalFetch.apply(this, arguments); return result.then(console.log('Request was sent')); }; })(fetch); fetch('//api.github.com/orgs/axios') .then(response => response.json()) .then(data => { console.log(data) });
下載進度
進度指示器在加載大型資產時非常有用,尤其是對于用戶網速慢。以前,JavaScript 程序員使用XMLHttpRequest.onprogress回調處理程序來實現進度指示器。
Fetch API沒有onprogress處理程序。相反,它提供了一個通過響應對象的 body 屬性的ReadableStream實例。
下面的例子說明了使用ReadableStream為(wei)用戶提(ti)供在圖(tu)像下載過程中的即時反(fan)饋
// original code: //github.com/AnthumChris/fetch-progress-indicators<div id="progress" src="">progress</div><img id="img"><script>'use strict'const element = document.getElementById('progress'); fetch('//fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg') .then(response => { if (!response.ok) { throw Error(response.status+' '+response.statusText) } // ensure ReadableStream is supported if (!response.body) { throw Error('ReadableStream not yet supported in this browser.') } // store the size of the entity-body, in bytes const contentLength = response.headers.get('content-length'); // ensure contentLength is available if (!contentLength) { throw Error('Content-Length response header unavailable'); } // parse the integer into a base-10 number const total = parseInt(contentLength, 10); let loaded = 0; return new Response( // create and return a readable stream new ReadableStream({ start(controller) { const reader = response.body.getReader(); read(); function read() { reader.read().then(({done, value}) => { if (done) { controller.close(); return; } loaded += value.byteLength; progress({loaded, total}) controller.enqueue(value); read(); }).catch(error => { console.error(error); controller.error(error) }) } } }) ); }) .then(response => // construct a blob from the data response.blob() ) .then(data => { // insert the downloaded image into the page document.getElementById('img').src = URL.createObjectURL(data); }) .catch(error => { console.error(error); })function progress({loaded, total}) { element.innerHTML = Math.round(loaded/total*100)+'%'; }</script>
在 Axios 中實現進度指示器更簡單,特別是如果您使用Axios 進(jin)度條模塊。首先(xian),您(nin)需(xu)要包含以下樣式和(he)腳本。
<link rel="stylesheet" type="text/css" href="//cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/nprogress.css" /><script src="//cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/index.js"></script>
然后你可以像這樣實現進度條
<img id="img"><script>loadProgressBar();const url = '//fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg';function downloadFile(url) { axios.get(url, {responseType: 'blob'}) .then(response => { const reader = new window.FileReader(); reader.readAsDataURL(response.data); reader.onload = () => { document.getElementById('img').setAttribute('src', reader.result); } }) .catch(error => { console.log(error) }); } downloadFile(url);</script>
此代碼使用FileReader API 異步讀取下載的圖像。readAsDataURL方法以Base64 格式返回圖像數據編碼后的字符串,然后插入到img標簽的src屬性中顯示圖像。
并發請求
為了同時發出多個請求,Axios 提供了axios.all()方法。只需將一組請求傳遞給此方法,然后使用axios.spread()分配響應數(shu)組(zu)的屬性(xing)來分隔變量:
axios.all([ axios.get('//api.github.com/users/iliakan'), axios.get('//api.github.com/users/taylorotwell') ]) .then(axios.spread((obj1, obj2) => { // Both requests are now complete console.log(obj1.data.login + ' has ' + obj1.data.public_repos + ' public repos on GitHub'); console.log(obj2.data.login + ' has ' + obj2.data.public_repos + ' public repos on GitHub'); }));
您可以使用內置的Promise.all()方法實現相同的結果。將所有獲取請求作為數組傳遞給Promise.all()。接下來,處理響應通過使用異步(bu)函數,如下所示:
Promise.all([ fetch('//api.github.com/users/iliakan'), fetch('//api.github.com/users/taylorotwell') ]) .then(async([res1, res2]) => { const a = await res1.json(); const b = await res2.json(); console.log(a.login + ' has ' + a.public_repos + ' public repos on GitHub'); console.log(b.login + ' has ' + b.public_repos + ' public repos on GitHub'); }) .catch(error => { console.log(error); });
結論
Axios 在一個緊湊的包中為您的大部分 HTTP 提供了一個易于使用的 API,以滿足痛心的需要。但是,如果您更喜歡堅持使用本機 API,則沒有什么阻止您實現 Axios 功能。正如本文所討論的,完全有可能重現使用Web 瀏覽器提供的fetch()方法的 Axios 庫。
最終,是否值得(de)加載(zai)客(ke)戶端 HTTP API 取決(jue)于您對使用內置(zhi) API 感到很自在。
(本文由聞數起舞翻譯自LogRocket的文章《Axios or fetch(): Which should you use?》,轉載請注明出處,原文鏈接:
//blog.logrocket.com/axios-or-fetch-api/)