專案我选择了Fetch而不是Axios(比較)
===

---
###### tags: `Fetch`, `Axios`, `2024`
Axios在很早期的時候的確改善了JS原生的XMLHTTPRequest的複雜設定,就好像Redux 設定createSlide,reducer 一樣,如果很輕鬆地資料傳遞,我也不會選擇Redux去做資料傳遞。一直到出現了框架,和JS越來越成熟以後,fetch 顯然更加的穩定。
```jsx!
const req = new XMLHttpRequest();
req.addEventListener("load", function() {
console.log(JSON.parse(this.responseText))
})
req.open('GET', 'https://jsonplaceholder.typicode.com/todos/')
req.send()
```
- 這是 XMLHTTPRequest 的做法。
<br>
---
```jsx!
const data = (await axios.get('https://jsonplaceholder.typicode.com/todos/')).data
```
在這裡我們能發現Axios的確簡化了XMLHttpRequest的寫法。當然Axios還補充了非常多的功能例如 cache。可是就像上面說的fetch 越來越成熟了,然後遇上SSR,我就開始選擇Fetch。
## Axios VS Fetch 的基本差異:
### axios:
- 基於 Promise 的 HTTP 客戶端:
- 適用於瀏覽器和Nodejs。
- 自動轉換JSON數據:
- 發送請求時,Axios 會自動將請求數據轉換為JSON字符串,接受到響應後也會自動處理JSON數據。
- 請求和響應攔截器:
- 允許你在請求或響應被then 或 catch 處理之前攔截它們。
- 客戶端支持防禦XSRF:**~~請繼續看下去!~~**
<br>
```jsx!
import axios from 'axios';
axios.get('https://api.example.com/data')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log('Error', error.message);
});
// 发送 JSON 数据
axios.post('https://api.example.com/data', {
name: 'John',
age: 30
});
```
<br>
### axios 的 XSRF/CSRF
- CXRF / XSRF 是設定axios的時候做的全局默認值,用來在發送請求時自動處理跨站請求偽造保護。用於確保在與後端交互時,正確地發送 CSRF 領牌。
- 在使用前端framework可能不常見,但完全可以在客戶端使用類似的設定。
- 尤其是當你的應用需要, 需要 CSRF 保護的後端服務器交互時。
- 這些設置幫助確保每個由axios發出的請求都攜帶了正確的 CSRF 領牌,這樣服務器可以驗證請求的合法性。
### XSRF/CSRF 的解釋:
1. xsrfCookieName :
- 這個設置告訴 Axios, 從那個cookie 中讀取CSRF令牌。
- 在這個例子中,他從名為 'XSRF-TOKEN'的cookie中讀取令牌。
2. xsrfHeaderName:
- 這個設置指定了將CSRF令牌放在哪個HTTP頭中發送給伺服器。
- 這裡使用的頭是 'X-XSRF-TOKEN'
這樣的設置確保每次 HTTP 請求都符合後端期望的 CSRF 防護策略,增加安全性。
在實際應用中,服務器必須設置正確的cookie,前端 Axios 客戶端則會自動處理這些cookie 和 頭信息。
### 實際設置:
```jsx!
// utils/axios.js
import axios from 'axios';
// 创建 Axios 实例
const axiosInstance = axios.create();
// 设置 CSRF 令牌的 cookie 名称和头部名称
axiosInstance.defaults.xsrfCookieName = 'XSRF-TOKEN';
axiosInstance.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';
export default axiosInstance;
```
- 創建 axios.js 文件
```jsx!
// pages/index.js
import axios from '../utils/axios';
export default function Home() {
async function fetchData() {
try {
const response = await axios.get('https://api.example.com/data');
console.log('Data:', response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
return (
<div>
<h1>Welcome to the Home Page</h1>
<button onClick={fetchData}>Fetch Data</button>
</div>
);
}
```
- 在你的頁面或組件中(nextjs 為範例),使用上面配置好的 Axios 實例來發送請求。
- 在這個範例裡,當用戶點擊按鈕觸發了 fetchData,該function 會通過預先配置的 Axios 實例發送一個 GET 請求到 API連結。 由於 Axios 實例已經配置了 CSRF 令牌的名稱和頭部信息,它會自動處理與 CSRF 保護相關的邏輯。
<br>
---
### Fetch:
- 瀏覽器內置的API:
- 不需要額外安裝,fetch()會返回一個Promise,使得異步處理更加直觀
- 不自動處理JSON:
- 需要手動將響應數據轉換為JSON
- Stream 接口:
- fetch()支持讀取數據流,適用於處理大量書如視頻或大文件下載。
```jsx!
fetch('https://api.example.com/data')
.then(response => response.json()) // 手动解析JSON
.then(data => {
console.log(data);
})
.catch(error => {
console.log('Error', error.message);
});
// 发送 JSON 数据
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John',
age: 30
})
});
```
## 性能對比:
- 就性能而言,fetch 和 Axios 在大多數日常應用中的差異並不顯著。
- fetch 作為原生API,可能在處理某些特定任務時表現更好,如流處理或減少非必要的功能開銷。
- Axios的性能優化也非常出色,尤其是在處理大量的並發請求時。
- fetch屬於原生瀏覽器內置,跟Axios不一樣,是額外安裝的,代表者既然fetch能做到的,使用者還要額外裝一個已經成熟的套件。
- fetch並不支援較舊的瀏覽器,這時候只能用 axios 來支援。
## 功能覆蓋:
- 其實fetch 並沒有涵蓋 Axios 的所有功能。
- Axios提供了更廣泛的攔截器,更方便的錯誤處理,以及更好的舊瀏覽器處理。
- fetch則需要額外的配置或封裝才能達到相同的功能。
- 但其實非同步的處理,他們都一樣。
<br>
## Axios的不足之處
僅管Axios 是一個廣受歡迎的 HTTP 客戶端庫,雖然被廣泛用於前端開發,但它並不是沒有缺點。
<br>
### bundle 太大
```jsx!
import axios from 'axios';
axios.get('https://api.example.com/data')
.then(response => console.log(response.data))
.catch(error => console.error('Error', error));
```
```jsx!
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error', error));
```
- Axios 就像上面所說的,它是一個需要額外下載的套件,這對於需要加載速度極快的應用來說可能是一個問題。尤其是移動設備例如 websocket,每次傳遞都講究速度的話都至關重要。
### 依賴性
- Axios 是一個第三方庫,這意味著他的維護和更新依賴於開發團度和維護者。如果項目暫停維護,可能會導致安全和功能上的風險。
### 錯誤處理:
```jsx!
axios.get('https://api.example.com/data')
.then(response => {
if (response.status >= 200 && response.status < 300) {
console.log(response.data);
} else {
throw new Error(response.status);
}
})
.catch(error => console.error('Request failed', error));
```
- Axios 在處理返回非 2xx 狀態碼的 HTTP 響應時不會跑出錯誤,而是正常返回響應對象。
- 這要求開發者必須檢查狀態碼,才能確定是否處理請求錯誤。
<br>
## 為什麼我選擇使用fetch ?
雖然現在存在很多種方法和庫來處理這些請求,如Axios,jQuery.ajxa 等,但許多開發者包含我都會選擇使用原生的fetch去做非同步。
<br>
### 現代化和簡潔性
```jsx!
fetch('https://api.example.com/data')
.then(response => response.json()) // 转换响应为 JSON
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
- fetch 是現代瀏覽器提供的內置API,不需要額外的依賴或庫就能在大多數環境中運行。
- 與Axios相比,fetch提供了一個更簡潔的藉口,讓開發者可以直接使用而不必擔心第三方庫的依賴管理和更新。
<br>
### 控制性和配置能力
```jsx!
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John', age: 30 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
- fetch 提供了相近的配置選項,包括 headers,credentials,cache 策略等。
- 這些配置在fetch調用中直接作為第二個參數傳遞,使得控制請求行為變得更直觀和靈活。
<br>
### 流處理能力:
```jsx!
fetch('https://api.example.com/large-data')
.then(response => {
const reader = response.body.getReader();
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
console.log(value);
return reader.read().then(processText);
});
})
.catch(error => console.error('Error:', error));
```
- fetch 支持流式讀取響應體,這對於處理大型數據(如影片流,大型文件下載)特別有用。
- 這種處理方式在axios中應該不支持,不然就是實現起來比較複雜。
<br>
### 標準化和未來兼容
- 作為一個 web 標準,fetch得到了廣泛的支持和持續的更新。
- 這保證了與現代瀏覽器的兼容性和功能的持續增強。
- 而像Axios的第三方庫可能會因為維護不當或更新延遲而影響其使用壽命和安全性
<br>
## 總結:
其實我一直都偏原生主義使用者,不管是設計任何額外功能或者已經存在的套件類功能也好,我都喜歡自己下去創建一組,這樣我可以隨意地變更成適應任何狀況的專案。在新的專案裡決定使用 NextJS 以後,就開始認真的閱讀和使用原生的 fetch 功能。但也因為技術長規定需要使用Axios的話,我也會選擇尊重啦...
以上的介紹並沒有真正地表明我自己會站在哪一方,如果我今天是專案管理者,我也會考量自己的專案是否需要Axios的功能,畢竟我在意的點是 '是否真的需要多載一個包來做非同步'。如果大家都覺得用fetch 就好,那就沒有必要一定要用 axios。
好,希望這個文章能幫到你們能更加了解原生強大的 fetch 和 Axios。我們下一篇再見!面試的你們也加油!PEACE!
