因為Axios的易于使用,所以有些開發人員比起內置的API,更喜歡Axios。
但許多人高估了這個庫。
fetch() API不但完全能夠重現Axios的關鍵功能,而且還有隨時可用于所有現代瀏覽器中的獨特優勢。
在本文中,我將按照基本語法、向后兼容性、響應超時、自動JSON數據轉換、HTTP攔截器、下載進度、同時請求這些方面來比較fetch()和Axios,看看它們如何執行任務。
希望在本文結束時,大家對這兩個API有了更深入的了解。
在我們深入研究Axios更高級地功能之前,先與fetch()進行基本語法的比較。
下面是Axios如何將帶有自定義請求頭的[POST]請求發送到指定URL的代碼:
// axiosconst url = 'https://jsonplaceholder.typicode.com/posts'const data = { a: 10, b: 20,};axios .post(url, data, { headers: { Accept: "application/json", "Content-Type": "application/json;charset=UTF-8", }, }) .then(({data}) => { console.log(data);});
與fetch()版本進行比較:
// fetch()const url = "https://jsonplaceholder.typicode.com/todos";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) => response.json()) .then((data) => { console.log(data); });
注意:
Axios的主要賣點之一是其廣泛的瀏覽器支持。
即使是像IE11這樣的舊瀏覽器也可以毫無問題地運行Axios。這是因為它背后使用了XMLHttpRequest。
而fetch()僅支持Chrome 42+,Firefox 39+,Edge 14+和Safari 10.3+。
如果你使用Axios的唯一原因是向后兼容性,那么實際上并不需要HTTP庫。而且,你可以將fetch()與polyfill一起使用,在不支持fetch()的web瀏覽器上實現類似的功能。
要使用fetch() polyfill,可以通過npm命令進行安裝,如下所示:
npm install whatwg-fetch --save
然后,提出如下請求:
import 'whatwg-fetch'window.fetch(...)
謹記,在有些舊瀏覽器中,可能還需要promise polyfill。
在Axios中設置超時的簡單性,是一些開發人員比fetch()更喜歡Axios的原因之一。
在Axios中,你可以使用配置對象的timeout屬性來設置請求中止之前的毫秒數。
例如:
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接口提供類似的功能。
不過,它的代碼不如Axios版本簡單:
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.abort()構造函數創建AbortController對象,它允許我們稍后中止請求。
Signal是AbortController的只讀屬性,提供了一種與請求通信或中止請求的方法。
如果服務器在4秒內沒有響應,則調用controller.abort(),終止操作。
如前所述,Axios在發送請求時會自動字符串化數據(當然你也可以覆蓋默認行為并定義不同的轉換機制)。
但是,當使用fetch()時,你必須手動執行此操作。
比較:
// axiosaxios.get('https://api.github.com/orgs/axios') .then(response => { console.log(response.data); }, error => { console.log(error); });
// fetch()fetch('https://api.github.com/orgs/axios') .then(response => response.json()) // one extra step .then(data => { console.log(data) }) .catch(error => console.error(error));
自動轉換數據是一個不錯的功能,但同樣,這不是你不能用fetch()做的事情。
Axios的主要功能之一是它能夠攔截HTTP請求。
當你需要檢查或更改從應用程序到服務器的HTTP請求時,使用HTTP攔截器非常方便,從服務器到應用程序亦是如此(例如,日志記錄、身份驗證或重試失敗的HTTP請求)。
使用攔截器就不必為每個HTTP請求編寫單獨的代碼。
在你想要為處理請求和響應設置全局策略時,HTTP攔截器非常有用。
以下是在Axios中聲明請求攔截器的方法:
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('https://api.github.com/users/sideshowbarker') .then(response => { console.log(response.data); });
上面的代碼中,axios.interceptors.request.use()方法用于定義發送HTTP請求之前要運行的代碼。而axios.interceptors.response.use()用于攔截來自服務器的響應。
假設存在網絡錯誤,那么通過響應偵聽器,可以重試相同的請求。
默認情況下,fetch()不提供攔截請求的方法,但它的解決方法也并不復雜。
那就是覆蓋全局fetch()方法并定義自己的攔截器,如下所示:
fetch = (originalFetch => { return (...arguments) => { const result = originalFetch.apply(this, arguments); return result.then(console.log('Request was sent')); };})(fetch);fetch('https://api.github.com/orgs/axios') .then(response => response.json()) .then(data => { console.log(data) });
進度條在加載時非常有用,尤其是對于互聯網速度較慢的用戶。
以前,JavaScript程序員使用XMLHttpRequest.onprogress回調處理程序來實現進度指示器。
Fetch API沒有onprogress處理程序。事實上,它通過響應對象的body屬性來提供ReadableStream的實例。
以下示例表明如何使用ReadableStream在圖像下載期間為用戶提供即時反饋:
index.html<!-- Wherever you html is --> <div id="progress" src="">progress</div> <img id="img">script.js'use strict'const element = document.getElementById('progress');fetch('https://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)+'%';}
在Axios中實現進度指示器更簡單,尤其是在使用Axios進度條模塊時。
首先,包含以下樣式和腳本:
// the head of your HTML <link rel="stylesheet" type="text/css" />// the body of your HTML <img id="img" /> <button onclick="downloadFile()">Get Resource</button> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/index.js"></script>// add the following to customize the style<style> #nprogress .bar { background: red !important; } #nprogress .peg { box-shadow: 0 0 10px red, 0 0 5px red !important; } #nprogress .spinner-icon { border-top-color: red !important; border-left-color: red !important; }</style>
然后像這樣實現進度條:
<script type="text/javascript"> loadProgressBar(); function downloadFile() { getRequest( "https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg" ); } function getRequest(url) { axios .get(url, { responseType: "blob" }) .then(function (response) { const reader = new window.FileReader(); reader.readAsDataURL(response.data); reader.onload = () => { document.getElementById("img").setAttribute("src", reader.result); }; }) .catch(function (error) { console.log(error); }); } </script>
代碼使用FileReaderAPI異步讀取下載的圖像。
readAsDataURL方法以Base64編碼字符串的形式返回圖像的數據,然后將其插入到img標記的src屬性中以顯示圖像。
為了同時發出多個請求,Axios提供axios.all()方法。
只需將請求數組傳遞給此方法,然后使用axios.spread()將響應數組的屬性分配給單獨的變量:
axios.all([ axios.get('https://api.github.com/users/iliakan'), axios.get('https://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()方法獲得相同的結果。
將所有fetch請求作為數組傳遞給Promise.all()。接著使用async函數處理響應,如下所示:
Promise.all([ fetch('https://api.github.com/users/iliakan'), fetch('https://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在緊湊的軟件包中提供了一個易于使用的API,可滿足大多數HTTP通信需求。
而web瀏覽器提供的fetch()方法則能完全重現Axios庫的主要功能。
所以,是否加載客戶端HTTP API取決于你是否習慣使用內置API。
編程快樂!
本文鏈接:http://www.www897cc.com/showinfo-26-77835-0.htmlAxios vs. fetch():哪個最適合 HTTP 請求?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com