自用 fetch封装

当业务需求增加时可能会持续更新

目录结构

-- api
    -- customFetch.js    // 因目前 fetch 无timeout功能,扩展 fetch 函数令其支持timeout
    -- index.js    // 总接口文件
    -- request.js    // 实际 request 类

 customFetch.js

// 原有fetch方法
const oldFetchfn = fetch;

// 扩展原有fetch方法
export default function (input, opts) {
  const fetchPromise = oldFetchfn(input, opts);

  // 设置定时器,如果定时器先抛出reject则表示fetch已超时
  const timeoutPromise = new Promise(function (resolve, reject) {
    setTimeout(() => {
      reject(new Error("request timeout"))
    }, opts.timeout || 20000)
  });

  //哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
  return Promise.race([fetchPromise, timeoutPromise]);
}

request.js

import { cloneDeep } from 'lodash'
import { message } from 'ant-design-vue';
import customFetch from './customFetch';

export default class Request {
  constructor(url, data, methods, options) {
    this.create(url, data, methods, options);
  }

  url = "";
  initObject = {};
  /**
   * @param showAlert // 是否展示错误提示弹窗
   * @param responseType
   * @param timeout
   * @param redirectToLogin // 是否在登录态失效时跳转login页面(未实现,预留)
   */
  options = {
    showAlert: true, // 弹出message错误提示
    responseType: 'json', // 'json' 'blob' 'arraybuffer' 'text'
  };

  // 将 object 转为 querystring 键值对形式
  // e.g: { property1: 123 } -> property1=123
  stringifyQueryString(obj, arr = [], idx = 0) {
    const arrCopy = cloneDeep(arr);
    for(let item in obj){
      arrCopy[idx++] = [item, obj[item]];
    }
    return new URLSearchParams(arrCopy).toString();
  }

  // 构造fetch第二个入参 initObject
  createInitObject(data, method, options) {
    const headers = new Headers({
      "Content-Type": "application/json"
    });
    let initOptions = {
      method,
      credentials: 'same-origin',
      headers
    }
    if(options.timeout){
      initOptions = Object.assign(initOptions, {
        timeout: options.timeout,
      })
    }
    if(!['get', 'head'].includes(method.toLowerCase())){
      initOptions = Object.assign(initOptions, {
        body: JSON.stringify(data),
      })
    }
    return initOptions;
  }

  // 初始化(载入url, 配置initObject,配置options)
  create(url, data, method, options) {
    let urlOption = url;
    if(['get', 'head'].includes(method.toLowerCase())){
      urlOption = `${url}${data ? '?' : ''}${this.stringifyQueryString(data)}`;
    }
    const initObject = this.createInitObject(data, method, options);

    this.url = urlOption;
    this.initObject = initObject;
    if(options && Object.keys(options).length){
      this.options = options;
    }
  }

  // 调用fetch
  run() {
    return customFetch(this.url, this.initObject).then(res => {
      if(!res.ok){
        this.options.showAlert && message.error(res.statusText)
        return res.json();
      }
      let result = undefined;
      // 在接收文件时,可能会接收到错误提示,如果responseType为“application/json”时则忽视options.responseType强行转为json
      if (res.headers.get('content-type').includes('application/json')) {
        result = res.json();
      } else {
        switch(this.options.responseType) {
          case 'blob':
            result = res.blob();
            break;
          case 'arraybuffer':
            result = res.arrayBuffer();
            break;
          default:
            try{
              result = res.json();
            } catch (e) {
              result = res.text();
            }
            break;
        }
      }
      return result;
    }).catch(err => {
      if(err.message === 'request timeout'){
        this.options.showAlert && message.error("请求超时");
      } else {
        this.options.showAlert && message.error("网络错误");
      }
      return err;
    });
  }
}

index.js

import Request from "./request";

export default {
  test(data, options = {}) {
    const url = "/api/planmap/querysswplanningsite";
    return new Request(url, data, 'GET', options).run();
  }
}

调用

import api from "@/api";

api.test({test: 123}).then(res => {
  console.log(res)
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值