【vue】fetch封装

  • fetch 必然要替换 XMLHttpRequest ,所以是时候尝试 fetch 了;
  • 本封装仅针对npm引入;
  • 本封装依赖 es6-promisewhatwg-fetch,分别对 promisefetch 进行兼容性处理;
  • 还有一种兼容性处理是依赖 es6-promiseisomorphic-fetch ,但是看它的源码就会发现,isomorphic-fetch 只不过是引用了 whatwg-fetch ,并没有做二次开发,isomorphic-fetch 只是将fetch添加为全局,以便其API在客户端和服务器之间保持一致,所以没必要。

封装的主要内容

  1. fetch 的请求方式同 $ajaxaxios 都不太一样,并且它本身的get请求同其他请求对数据的处理和herder也不太相同,所以为了统一请求行为,方便请求过程,将请求过程进行封装;
  2. fetch 请求的结果均返回到.then()中,但是平时的习惯是是在 .then() 中处理正确结果,.catch() 中处理错误,所以对请求结果进行统一处理;
  3. fetch 本身没有 请求超时 这个概念,所以通过 Promise.race 来处理,它的作用是多个promise同时运行,返回的结果以最快返回结果的那个promise的值为准。

封装的代码

// 处理promise和fetch的兼容性以及引入
require('es6-promise').polyfill()
import 'whatwg-fetch'

// 前置拼接url
const api = '***'

// 自定义headers
const headers = {
  'Accept': 'application/json; version=3.13.0'
}

// 处理get请求,传入参数对象拼接
const formatUrl = obj => {
  const params = Object.values(obj).reduce((a, b, i) => `${a}${Object.keys(obj)[i]}=${b}&`, '?')
  return params.substring(0, params.length - 1)
}

/**
 * @param url    (String) 接口URL
 * @param option (Object) 参数对象,包括method(请求方式,不填默认'get'),headers(设置请求头,选填),data(请求参数,所有请求方式均适用)
 */
const recoFetch = (url, option = {}) => {
  // 设置请求超时的时间,默认10秒
  const timeout = option.timeout || 10000

  option.headers = option.headers || headers
  option.method = (option.method || 'get').toLocaleLowerCase()
  
  // 格式化get请求的数据(fetch的get请求需要需要将参数拼接到url后面)
  if (option.method === 'get') {
    if (option.data) {
      url = url + formatUrl(option.data)
    }
  }

  // 对非get类请求头和请求体做处理
  if (option.method === 'post' || option.method === 'put' || option.method === 'delete') {
    option.headers['Content-Type'] = option.headers['Content-Type'] || 'application/json'

    // 非get类请求传参时,需要将参数挂在body上
    option.body = JSON.stringify(option.data)

    // 根据后台要求,如果有时候是java请求会用qs转
    // option.body = qs.stringify(option.data)
  }
  delete option.data

  return addTimeout(fetch(api + url, option), timeout)
}

// 对请求结果进行处理:fetch请求成功后返回的是json对象
function parseJSON (response) {
  return response.json()
}

// 
/**
 * 增加超时处理:fetch本身是没有请求超时处理的,所以可以通过
 * @param fetchPromise (Promise) fetch请求
 * @param timeout      (Number)  请求超时的时间
 */
function addTimeout (fetchPromise, timeout) {
  let timeoutFn = null

  // 请求超时的Promise
  var timeoutPromise = new Promise((resolve, reject) => {
    timeoutFn = function () {
      reject({
        code: 'timeOut',
        text: '请求超时,请重试'
      })
    }
  })

  // 声明Promise.race
  const racePromise = Promise.race([
    fetchPromise,
    timeoutPromise
  ])

  setTimeout(function () {
    timeoutFn()
  }, timeout)

  const racePromiseResult = new Promise((resolve, reject) => {
    let status = 0

    racePromise
      .then(response => {
        status = response.status
        return response
      })
      .then(parseJSON)
      .then(response => {
        // 将状态码添加到返回结果中,以备后用
        response.status = status

        // 如果返回码在300到900之间,将以错误返回,如果需要对错误统一处理,可以放在下面判断中
        if (/^[3-9]\d{2}$/.test(response.status)) {
          reject(response)
        }

        // 否则以正确值返回
        resolve(response)
      })
      .catch(error => {
        // 请求出错则报错 recoFetch Error: ***
        console.log('recoFetch Error:', error)
      })
  })

  // 将racePromise的结果返回
  return racePromiseResult
}

export default recoFetch

个人博客:午后南杂

猜你喜欢

转载自www.cnblogs.com/luanhewei/p/9643528.html