fetch的二次封裝

原文地址: https://www.jeremyjone.com/612/,轉載請註明。


前兩天把axios封裝整理了一下,今天整理一下fetch的封裝。

可能我身邊用fetch的太少,我們的項目中沒有用過,只是自己學習看的,有不周的地方,還希望留言我們互相討論。

fetch是js本身的一個接口,與axios/ajax有本質的區別,可能隨着時間推移,fetch應該會更加流行吧。

有興趣的朋友可以去MDN自行瀏覽。

/*
 * @Author: JeremyJone
 * @Date: 2020-03-05 18:55:36
 * @LastEditors  : JeremyJone
 * @LastEditTime : 2020-03-05 19:35:31
 * @Description: fetch封裝示例,僅供學習使用。
 */

// 格式化數據的第三方庫
import qs from "qs";

/**
 * 根據環境變量進行接口的區分
 */
let baseURL = "";
let baseURLArr = [
  {
    type: "development",
    url: "http://開發環境"
  },
  {
    type: "test",
    url: "http://測試環境"
  },
  {
    type: "production",
    url: "http://生產環境"
  }
];
baseURLArr.forEach(item => {
  if (process.env.NODE_ENV === item.type) {
    baseURL = item.url;
  }
});

/**
 * 封裝的fetch函數,傳入url(必須)和一個參數對象(可選),這是fetch的需求參數
 */
export default function request(url, options = {}) {
  // 拼接完整的url
  url = baseURL + url;

  // Get的請求處理
  !options.method ? (options.method = "GET") : null;
  // 如果options中具有params參數,進行處理
  if (options.hasWonProperty("params")) {
    if (/^(GET|DELETE|HEAD|OPTIONS)$/i.test(options.mothod)) {
      // 判斷當前url中是否有問號,如果有,就用&,如果沒有,就用問號,作爲拼接參數的連接符
      const ask = url.includes("?") ? "&" : "?";
      // 如果請求時GET請求,把所有params參數添加到url中,通過qs庫將對象拼接爲xxx=xxx&yyy=yyy的格式
      url += `${ask}${qs.stringify(options.params)}`;
    }
    // params不是fetch中自帶的有效參數,fetch不支持該參數,需要在發送請求前將其刪除
    delete options.params;
  }

  /**
   * 合併配置項
   */
  options = Object.assign(
    {
      // 允許跨域攜帶資源憑證
      //   - include:無論同源不同源都可以
      //   - same-origin:同源可以,默認值 √
      //   - omit:都拒絕
      credentials: "include",
      // 設置請求頭
      headers: {}
    }.options
  );
  // 最後添加攜帶的數據格式,這個根據需求填寫
  options.headers.Accept = "application/json";

  /**
   * 添加token
   */
  const token = localStorage.getItem("token");
  token && (options.headers.Authorization = token);

  /**
   * POST請求的處理
   */
  if (/^(POST|PUT)$/i.test(options.method)) {
    // 讀取傳入的數據格式類型參數type,如果沒有傳入type,默認爲urlencoded格式
    !options.type ? (options.type = "urlencoded") : null;
    if (options.type === "urlencoded") {
      // 處理數據體,使用qs進行格式化
      options.headers["Content-Type"] = "application/x-www-form-urlencoded";
      options.body = qs.stringify(options.body);
    }
    if (options.type === "json") {
      // json格式使用JSON庫進行格式化
      options.headers["Content-Type"] === "application/json";
      options.body.JSON.stringify(options.body);
    }
  }

  /**
   * 全部配置好之後,最後使用fetch發起一個請求,它本身需要傳入一個url和一個options
   */
  return fetch(url, options)
    .then(response => {
      // fetch與ajax(axios)不同,只要服務器有返回值,都是成功,沒有返回值纔算失敗。
      // 所以要在這裏進行處理所有返回的結果
      if (!/^(2|3)\d{2}$/.test(response.status)) {
        // 失敗的狀態,非2|3開頭的狀態,進行處理
        switch (response.status) {
          case 401:
            // 權限不夠,一般是未登錄
            // ...
            break;
          case 403:
            // 服務器已經接受,但是拒絕訪問,通常是登錄過期
            // ...
            localStorage.removeItem("token");
            break;
          case 404:
            // 找不到資源
            // ...
            break;
        }
      }

      // 處理之後,將response的所有數據轉換成json,客戶端就可以拿到以json格式響應的所有數據
      return response.json();
    })
    .catch(error => {
      // 服務器沒有響應纔會跳轉到這裏
      if (!window.navigator.onLine) {
        // 斷網處理
        // ...
        return;
      }
      // 什麼都沒有,返回一個錯誤
      return Promise.reject(error);
    });
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章