从0到1封装小程序HTTP请求

2,899 阅读2分钟

前言

作为一个前端开发者,从最开始的js、jQuery一把梭,后来的vue、react、angular等MVVM、MVC框架,我们在开发工程中都离不开HTTP库的使用。

HTTP库

1、jQuery的$.ajax

调用了XMLHttpRequest对象,封装在相关函数在配置项中,一旦传入了必需选项,则直接调用相应的send()方法进行数据的请求

2、Axios

基于Promise的请求库,通过判断XMLHTTPRequest对象存在与否,来支持客户端和node服务端发送请求,封装的很不错的HTTP库,支持promise、拦截请求和响应等

小程序网络请求

wx.request({
  url: 'test.php', //仅为示例,并非真实的接口地址
  data: {
    x: '',
    y: ''
  },
  header: {
    'content-type': 'application/json' // 默认值
  },
  success (res) {
    console.log(res.data)
  }
})

小程序本身的请求已经封装的很不错了,使用起来和$.ajax相似,支持许多配置项的设置,但是缺少公共配置、响应和请求拦截等实用功能

第一步--创建请求实例

class Axios {
  constructor() {
    this.instance = null // 类的实例
    this.config = defaultConfig
  }

  create(instanceConfig) {
    const { config } = this
    // 创建实例的时候添加基本配置
    this.config = {
      ...config,
      ...instanceConfig
    }
    return this
  }

  // 单例
  static getInstance() {
    if (!this.instance) {
        this.instance = new Axios()
    }
    return this.instance
  }
}

创建实例

const axios = Axios.getInstance()

promise包装小程序请求

const dispatchRequest = function(config) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...config,
      url: config.base + config.url,
      success: res => {
        resolve(res)
      },
      fail: res => {
        reject(res)
      }
    })
  })
}

给请求实例添加request方法

request(options) {
  const { config } = this
  // 实例请求的时候添加基本配置
  const requsetOptions = {
    ...config,
    ...options
  }
  return dispatchRequest(requsetOptions)
}

第二步--创建请求工具方法

创建实例,通过create设置基本配置项

const instance = (config = {}) => {
  return axios.create({
    base: globalApi,
    ...config
  })
}

创建请求工具方法,执行实例request

export function request(options) {
  const { baseConfig, url, method, data, isLogin } = options
  instance(baseConfig)
    .request({
      url,
      method: method || 'GET',
      data
    })
    .then(res => {
      options.success && options.success(res)
    })
    .catch(err => {
      if (options.error) {
        options.error(err)
      } else {
        errAlert()
      }
    })
  }
}

这样,一个请求的工具方法就完成了,但是这个方法现在只支持基本的请求和基本配置项的配置,还是缺少我们很常用的公共请求和响应的拦截。

第三部--添加请求和响应的拦截器

创建拦截器实例

class InterceptorManager {
  constructor() {
    this.fulfilled = null
    this.rejected = null
  }

  use(fulfilled, rejected) {
    this.fulfilled = fulfilled
    this.rejected = rejected
  }
}

在请求实例的构造方法中添加请求和响应拦截实例

constructor() {
  this.instance = null // 类的实例
  this.config = defaultConfig
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  }
}

在实例的request添加promise执行队列

request(options) {
    const { config, interceptors } = this
    // 实例请求的时候添加基本配置
    const requsetOptions = {
      ...config,
      ...options
    }

    const promiseArr = [] // promise存储队列

    // 请求拦截器
    promiseArr.push({
      fulfilled: interceptors.request.fulfilled,
      rejected: interceptors.request.rejected
    })

    // 请求
    promiseArr.push({
      fulfilled: dispatchRequest,
      rejected: null
    })

    // 回调拦截器
    promiseArr.push({
      fulfilled: interceptors.response.fulfilled,
      rejected: interceptors.response.rejected
    })

    let p = Promise.resolve(requsetOptions)
    promiseArr.forEach(ele => {
      p = p.then(ele['fulfilled'], ele['rejected'])
    })

    return p
  }

在请求工具方法中通过设置请求和响应的拦截方法

axios.interceptors.request.use(
  request => {
    return request
  },
  err => {
    console.error(err)
  }
)
axios.interceptors.response.use(
  response => {
    return response
  },
  err => {
    console.error(err)
  }
)

在请求拦截方法里面可以添加数据转换,在请求头部添加sign、token等,在响应拦截方法里面去做公共的数据处理等

最后

从零搭建一个简单的请求库很简单,但是想考虑的方方面面,设计好整个流程会比较麻烦,需要不断的改进和重构,本文的搭架过程参考了Axios的部分源码。