小程序请求封装和拦截器以及接口模块化

通常我们使用 axios 库中的 API 设置常用配置以及请求方法封装。更多详情,请查看:axios 常用配置以及请求方法封装。小程序中使用 wx.request  API 进行网络请求数据,但是小程序中未对请求提供拦截 API。在 Taro 框架中,我们可以看的 Taro.addInterceptor(callback) API 可以使用拦截器在请求发出前或发出后做一些额外操作。这里的提供的拦截器:请求拦截和响应拦截是没有区分的。

一、请求封装

wx.request 参数说明:

属性类型默认值必填说明最低版本
urlstring 开发者服务器接口地址 
datastring/object/ArrayBuffer 请求的参数 
headerObject 设置请求的 header,header 中不能设置 Referer。
content-type 默认为 application/json
 
timeoutnumber 超时时间,单位为毫秒2.10.0
methodstringGETHTTP 请求方法 
dataTypestringjson返回的数据格式 
responseTypestringtext响应的数据类型1.7.0
enableHttp2booleanfalse开启 http22.10.4
enableQuicbooleanfalse开启 quic2.10.4
enableCachebooleanfalse开启 cache2.10.4
successfunction 接口调用成功的回调函数 
failfunction 接口调用失败的回调函数 
completefunction 接口调用结束的回调函数(调用成功、失败都会执行)

object.method 的合法值:OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT。

通常我们的接口请求主要为 POST 和 GET 请求两种方式。更多详情参数,请查看:Taro 官网之 Taro.request API

url 为必传参数,data、method、header 为非必传参数。

class HTTP {
  request({
    url,
    data = {},
    method = 'GET',
    header = {'content-type': 'application/json'}
  }) {
    return new Promise((resolve, reject) => {
      this._request(url, resolve, reject, data, method, header)
    }).catch((reject) => {
      console.log('catch', reject)
    })
  }
}
export { HTTP }

之所以要封装一下 wx.request API 的缘由:首先我们请求时,有些接口需要在请求前添加 loading 样式,待到请求结果响应时,将 loading 样式隐藏,同时接口中可能需要添加请求头之类的。

class HTTP {
  // data 默认空, method 默认为 GET
  _request(url, resolve, reject, data = {}, method = 'GET', header = {'content-type': 'application/json'}) {
    let headerParam = { 
      Authorization: wx.getStorageSync("tokenInfo").token
    };
    this._show()
    Taro.request({
      url,
      method,
      data,
      header: {
        ...header,
        ...headerParam,
      },
      success: (res) => {
        wx.hideLoading()
        if (res.statusCode == 200) {
          resolve(res.data)
        } else {
          reject()
        }
      },
      fail: (err) => {
        wx.showToast({
          title: '服务器网络错误!',
          icon: 'loading',
          duration: 1500
        })
        reject()
      }
    })
  }
  _show(){
    wx.showLoading({
      title: '加载中',
    })
  }
}

export { HTTP }

在接口定义文档中,我们只需采用 class 的 extends 继承封装的请求方法。

// src/servers/servers.js
import { HTTP } from '../utils/http.js'

const API = {
  login: "login/decodeUserInfo", // 登录
  ......
}
class MineModel extends HTTP {
  // 登陆
  getLogin(encryptedData, iv, code){
    return this.request({
      url: API.login,
      data: {
        encryptedData,
        iv,
        code,
      },
      method: 'POST',
      header: {
        'content-type': 'application/x-www-form-urlencoded'
      },
    })
  }
}
export { MineModel }

如何在页面中使用呢?

import {  MineModel } from '../../models/mine.js'

const mineModel = new MineModel()

// 请求第三方接口
mineModel.getLogin(res.encryptedData, res.iv, code).then(res => {
  console.log('请求第三方接口', res)
})

二、拦截器

在调用 Taro.request 发起请求之前,调用 Taro.addInterceptor 方法为请求添加拦截器,拦截器的调用顺序遵循洋葱模型。

拦截器是一个函数,接受 chain 对象作为参数。chain 对象中含有 requestParmas 属性,代表请求参数。拦截器内最后需要调用 chain.proceed(requestParams) 以调用下一个拦截器或发起请求。

// src/servers/interceptors.js
import { getNewToken } from "./servers";
const customInterceptor = (chain) => {
  const requestParams = chain.requestParams;
  return chain.proceed(requestParams).then((res) => {
    console.log(`http <-- ${url} result:`, res)
    return res
    // 对返回的信息做处理    
  })
};

比如 token 过期、请求服务器异常等问题。

Taro 提供了两个内置拦截器 logInterceptor 与 timeoutInterceptor,分别用于打印请求的相关信息和在请求超时时抛出错误。

Taro.addInterceptor(Taro.interceptors.logInterceptor)
Taro.addInterceptor(Taro.interceptors.timeoutInterceptor)
Taro.request({ url })

当然我们可以将拦截器放在一个数组中,代码如下:

const interceptors = [customInterceptor, Taro.interceptors.logInterceptor];

export default interceptors;

在加载请求方式中,采用 forEach 对拦截器中的每一项进行循环添加。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

更新

接口封装:

import Taro from "@tarojs/taro";
import getBaseUrl from "./baseUrl";
class HttpRequest {
  baseOptions(params, method = "GET", isShowLoading = true) {
    isShowLoading && Taro.showLoading({ title: "加载中", mask: true });
    let { url, data, contentType } = params;
    let headerParam = {
      Authorization: "bearer" + " " + Taro.getStorageSync("tokenInfo")
    };
    const BASE_URL = getBaseUrl(url);
    return new Promise((resolve, reject) => {
      Taro.request({
        url: BASE_URL + url,
        data: data,
        method: method,
        header: {
          "content-type": contentType,
          ...headerParam
        },
        success(res) {
          isShowLoading && Taro.hideLoading();
          resolve(res.data)
        },
        fail(e) {
          const errRes = err.hasOwnProperty("data")
            ? err.data
            : { succeed: false, errorMsg: "请求异常" };
          reject(errRes);
        }
      });
    })
  }
  get(url, data = "", isShowLoading = true, contentType = "application/json") {
    let option = { url, data, contentType };
    return this.baseOptions(option, isShowLoading);
  }
  post(url, data, isShowLoading = true, contentType = "application/json") {
    let params = { url, data, contentType };
    return this.baseOptions(params, "POST", isShowLoading);
  }
}

export { HttpRequest }

在接口请求中,getBaseUrl 方法,根据不同的环境,配置不同的请求地址:

const getBaseUrl = () => {
  let BASE_URL = "";
  if (process.env.NODE_ENV === "development" || || process.env.BUILD_ENV === "dev") { // 开发 测试
    BASE_URL = "xxx";
  } else if(process.env.BUILD_ENV === "test") { // 测试
    BASE_URL = "xxx";
  } else if (process.env.BUILD_ENV === "prd") { // 生产
    BASE_URL = "xxx";
  }
  return BASE_URL;
};
export default getBaseUrl;

关于如何配置不同环境的配置,请参考:谈谈 process.env.NODE_ENV

接下来我们就是如何接口模块化?

// src/service/api/common.js
import { HttpRequest } from '@/service/request'
const URL = {
  wxPhoneLogin: '/TALLY/token/wxPhoneLogin.magpie',
}
// 方案一:
class Common extends HttpRequest {
  wxPhoneLogin (param) {
    return this.post(URL.wxPhoneLogin, param)
  }
}
// 方案二:
let request = new HttpRequest()
class Common {
  wxPhoneLogin (param) {
    return request.post(URL.wxPhoneLogin, param)
  }
}

export default new Common()

模块化的好处,我在这里就不说了,那么我们如何使用呢?

// src/service/index.js
import common from './api/common'
export {
  common,
}

// 接口调用文件
import { common } from '@/service'
common.wxPhoneLogin({ ...parame })

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值