【uniapp&微信小程序】封装uni.request()

前言

        在项目开发过程中,往往需要对请求进行二次封装,这篇文章将对uni.request()进行二次封装,并实现多个环境的请求配置,对请求方式,数据格式等进行封装,将请求做到最简化。

一.封装uni.request()

第一步基于uni.request()进行二次封装,集成项目开发中需要的参数及方法。

新建src/request/index.ts文件内容如下: 

/**
 * 创建request请求
 * @returns
 */
const request = <T = any>(
  url: string, //接口地址
  type: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT', //请求方式
  data: AnyObject, //请求的参数
  header: any //设置请求的 header
): Promise<T> => {
  // 拼接url  config.base后面会讲到
  let apiUrl = config.base + url
  // 这里是获取存在Store中的token,获取方式根据自身项目来
  const userStore = useUserStore()
  // 全局添加请求头
  let obj = {
    // 获取Store中的token || 获取本地存储的token
    'Authori-zation': (userStore.token || storage.getData("TOKEN") || ""),
  }
  if (header) {
    // 有无传入header,有则合并
    let headers = Object.assign(header, obj);
    header = headers;
  } else {
    header = obj
  }
  if (data) {
    // 清除无用参数
    Object.keys(data).forEach(key => {
      if (data[key] == null || data[key] == undefined || data[key] === '') {
        delete (data[key]);
      }
    })
  }

  return new Promise((resolve, reject) => {
    uni.request({
      url: apiUrl,
      method: type,
      data,
      header,
      success(res) {
        if (res.statusCode == 200) {
          const data: any = res.data;
          if (data.code == 0) {
            // 正常抛出数据
            resolve(data.data as T)
          } else {
            if(data.code == 401) {
              // 未登录
              uni.redirectTo({
                url: ""  //未登录跳转指定页面
              })
              uni.hideLoading();
              return reject(data);
            }
            // 错误数据
            uni.hideLoading();
            // 弹窗错误框,这里是自己封装组件,
            common.toastErr(data.message || "网络请求异常") 
            reject(data);
          }
        } else {
          console.log(data)
          uni.hideLoading();
          common.toastErr("网络请求异常")
          reject(data)
        }
      },
      fail(err) {
        console.log(err)
        uni.hideLoading();
        common.toastErr("网络请求异常")
        reject(err)
      }
    })
  })
}

二.根据环境配置请求地址

        上面我们已经对uni.request()进行了封装,前面代码中提到的config.base就是我们需要获取的地址,在项目开发过程中,往往会有多个环境,如开发环境、预生产环境、生产环境等等,那我们怎么根据不同环境来配置对应的请求地址或其他信息呢?

要做到根据不同环境读取不同配置信息,那我们这里就需要用到uni.getAccountInfoSync()方法,该方法可以获取当前小程序账号信息,其返回值miniProgram属性的envVersion值,就是我们想获取的当前小程序环境:

属性 类型 说明
envVersion string 小程序当前环境版本:develop开发板;trial体验版;release正式版

已经解决了获取环境问题,那我们就可以来配置不同环境啦,这里分三种环境:

  • dev 开发环境
  • test 测试环境
  • prod 生产环境

在src下新建config文件,其下dev,test,prod三个文件夹用来配置对应信息。

先对配置进行ts规范,因为项目中可能不知请求地址一个配置,可能还有应用地图的key等其他信息,我们可以统一配置,新建config/types.ts  如下:

export interface IConfig {
  // 接口主地址
  base: string;
  // 环境模式
  mode: string;
  // 地图key
  mapKey: string;
  // 密钥
  secretKey: string;
}

 接下来就是具体内容的配置,新建config/dev/index.ts如下:

// dev 开发环境
import {IConfig} from "../types";

const test: IConfig = {
  // #ifdef H5
  base: "",
  // #endif

  // #ifdef MP-WEIXIN
  base:'http://192.168.1.15:8090/api',
  // #endif
  // 模式
  mode: "dev",
  // 地图key
  mapKey: "",
  // Secret Key
  secretKey: ""
}

export default test;

 新建config/test/index.ts如下:

// test 测试环境
import {IConfig} from "../types";

const test: IConfig = {
  // #ifdef H5
  base: "",
  // #endif

  // #ifdef MP-WEIXIN
  base:'http://192.168.1.15:8090/api',
  // #endif
  // 模式
  mode: "test",
  // 地图key
  mapKey: "",
  // Secret Key
  secretKey: ""
}

export default test;

  新建config/prod/index.ts如下:

// prod 生产环境
import {IConfig} from "../types";

const test: IConfig = {
  // #ifdef H5
  base: "",
  // #endif

  // #ifdef MP-WEIXIN
  base:'http://www.baidu.com/api',
  // #endif
  // 模式
  mode: "prod",
  // 地图key
  mapKey: "",
  // Secret Key
  secretKey: ""
}

export default test;

上面三个文件中使用了#ifdef #endif 注释,这是因为我们的项目可能不只是在小程序上运行,如我开发过的项目就有一个溯原H5页面,那这时候就得区分不同平台,这里简单介绍一下如何区分:

 #ifdef #endif其实就是条件编译,条件编译是用特殊注释作为标记,在编译时根据特殊注释,将注释里面的代码编译到不同平台,其写法如下:

已 #ifdef #ifndef   %PLATFORM%  开头 ,中间部分写代码,以 #endif 结尾。

  • #ifdef :if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称,如H5,MP-WEIXIN 

所以上面三个文件中条件编译的意思就是只在微信小程序存在/只在H5页面存在。

此时我们已经准备好了三种环境下的配置,那么接下来就是对当前环境的判断及使用,在config下新建index.ts 内容如下: 

import { IConfig } from "./types";
import prod from "./prod";
import test from "./test";
import dev from "./dev";

let obj: IConfig;

// #ifdef MP-WEIXIN
const plat = uni.getAccountInfoSync().miniProgram.envVersion
if(plat === "release") {
  obj = prod
} else if(plat === "trial") {
  obj = test
} else {
  obj = dev
}
// #endif

// #ifdef H5
if(import.meta.env.MODE === "production") {
  obj = prod
} else if(import.meta.env.MODE === "test") {
  obj = test
} else {
  obj = dev
}
// #endif
export default obj;

这一文件中就用到了上面讲的获取当前环境的方法,来配置对应信息,前面在request/index文件中提到的config.base就是来自于此。

三.封装请求方式

        到这个位置其实我们的封装已经可以使用了,但是在实际开发中,还分有get,post,put,delete等请求方式,及json,form表单等数据格式,那为了后续开发的便捷,我们还有继续根据请求方式及数据格式封装请求,这一部分就继续写在request/index.ts 文件中:

/**
 * http get 请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const get = <T = any>(
  url: string,
  data: AnyObject
): Promise<T> => {
  return request(url, 'GET', data, {})
}

/**
 * http post json请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const postJ = <T = any>(
  url: string,
  data: AnyObject
): Promise<T> => {
  return request(url, 'POST', data, {
    'Content-Type': 'application/json'
  })
}

/**
 * http post form表单请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const postW = <T = any>(
  url: string,
  data: AnyObject
): Promise<T> => {
  return request(url, 'POST', data, {
    'Content-Type': 'application/x-www-form-urlencoded'
  })
}

/**
 * http put json请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const putJ = <T = any>(url: string, data: AnyObject): Promise<T> => {
  return request(url, 'PUT', data, {
    'Content-Type': 'application/json'
  })
}

/**
 * http put form表单请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const putW = <T = any>(url: string, data: AnyObject): Promise<T> => {
  return request(url, 'PUT', data, {
    'Content-Type': 'application/x-www-form-urlencoded'
  })
}
/**
 * http delete请求
 * @param url 请求接口
 * @param data 请求参数
 * @returns
 */
const del = <T = any>(url: string, data: AnyObject): Promise<T> => {
  return request(url, 'DELETE', data, {})
}


export default {
  get,
  postJ,
  postW,
  putJ,
  putW,
  del
}

四.调用请求

接下来我们就根据上面封装的请求来试一试效果吧,新建src/apis文件:

//引入封装方法
import http from "@/request";

export const getTest = () => http.get<any>(`url`, {})

export const postTest = (data:any) => http.postJ<any>(`url`, data)

总结 

        可以看到,封装之后的请求已经非常精简,配置好各个环境地址,根据请求方式,数据格式,选择对应的封装方法即可。

猜你喜欢

转载自blog.csdn.net/G_ing/article/details/129217209