码字,杂谈

fetch的二次封装

前两天把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);
    });
}

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注