Skip to content

Axios 封裝實戰:打造高效能且易維護的 API 請求層

在開發中大型專案時,如果每次發送 API 請求都要重複設定 timeoutheaders 或手動處理 401 錯誤,不僅程式碼冗餘,管理起來更是噩夢。為了提高 程式碼維護性擴充性,對 Axios 進行二次封裝是前端開發者的必修課。

為什麼需要封裝 Axios?

傳統的寫法會將邏輯與配置混在一起,如下所示:

js
axios({
  method: "get",
  url: "https://jsonplaceholder.typicode.com/users",
  timeout: 5000,
  headers: {
    "Content-Type": "application/json",
    Authorization: "xxx",
  },
})
  .then((res) => {
    console.log(res.data);
  })
  .catch((err) => {
    const status = err?.response?.status;

    if (status === 401) console.log("權限過期");
    if (status === 403) console.log("無此權限");

    console.log(err);
  });

小提醒

透過封裝,我們可以將 統一配置錯誤處理環境變數 抽離,實現更優雅的程式碼結構。

如何為 Axios 進行封裝

我們必須統一設定,如:請求標頭、狀態碼、超過請求的時間、不同環境設置不同接口,並將請求的方法再次封裝與設置請求與回應的攔截器。

Axios 實體化 (Create Instance)

利用 axios.create 建立實體,可以針對不同的 API 來源(如:測試環境 vs 正式環境)設置不同的基礎路徑。

  • baseURL:建議搭配環境變數,例如:process.env.VITE_API_URL 來切換環境。
  • timeout:統一設置請求超時時間,避免無限等待。
  • headers:設置預設的請求標頭。如果有特殊標頭以參數的方式傳入,將會覆蓋預設的請求標頭。
js
const instance = axios.create({
  baseURL:
    import.meta.env.VITE_API_URL || "https://jsonplaceholder.typicode.com",
  timeout: 5000,
  headers: {
    "Content-Type": "application/json",
  },
});

Axios 方法封裝 (API Methods)

將常用的 GETPOST 等方法再次封裝,自訂回傳格式,例如:直接回傳 res.data,能讓呼叫端的程式碼更乾淨。

js
const api = {
  async GET(endPoint, config = {}) {
    try {
      const res = await instance.get(endPoint, config);
      return res.data;
    } catch (err) {
      return Promise.reject(err);
    }
  },
  async POST(endPoint, data, config = {}) {
    try {
      const res = await instance.post(endPoint, data, config);
      return res.data;
    } catch (err) {
      return Promise.reject(err);
    }
  },
};

Axios 攔截器 (Interceptors) 的核心應用

攔截器是封裝的靈魂,它能在「請求送出前」與「回應收到後」進行加工。

請求攔截 (Request Interceptor)

主要用於 自動注入 Token。不需要在每次發送 API 時手動傳入 Authorization。

回應攔截 (Response Interceptor)

主要用於 統一錯誤處理,例如:401 自動登出、500 系統錯誤提示。

js
function interceptors() {
  instance.interceptors.request.use(
    (req) => req,
    (err) => {}
  );
  instance.interceptors.response.use(
    (res) => res,
    (err) => {}
  );
}

interceptors();

再做一點補強,如下:

js
function interceptors() {
  instance.interceptors.request.use(
    (req) => {
      const token = localStorage.getItem("token");

      if (token) req.headers.Authorization = `Bearer ${token}`;
      return req;
    },
    (err) => Promise.reject(err)
  );

  instance.interceptors.response.use(
    (res) => res,
    (err) => {
      switch (err?.response?.status) {
        case 401:
          console.log("權限過期");
          break;
        case 403:
          console.log("沒有權限");
          break;
        case 500:
          console.log("伺服器錯誤");
          break;
        default:
          console.log("網路有問題");
          break;
      }

      return Promise.reject(err);
    }
  );
}

interceptors();

參考來源:Axios

Axios 封裝的分層職責

透過這樣的結構,當 API URL 變更或需要新增全域錯誤提示時,您只需要修改一個地方,就能影響整個專案,這就是封裝的核心價值!

模組檔案主要職責
instance.js負責 axios.create 基礎設定與環境變數對應。
api.js封裝成更易讀的 GET / POST 方法,簡化回傳資料格式。
interceptors.js集中處理請求前的 Token 注入與回應後的狀態碼判斷。