当前位置:   article > 正文

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

uni.request

前言

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

一.封装uni.request()

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

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

  1. /**
  2. * 创建request请求
  3. * @returns
  4. */
  5. const request = <T = any>(
  6. url: string, //接口地址
  7. type: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT', //请求方式
  8. data: AnyObject, //请求的参数
  9. header: any //设置请求的 header
  10. ): Promise<T> => {
  11. // 拼接url config.base后面会讲到
  12. let apiUrl = config.base + url
  13. // 这里是获取存在Store中的token,获取方式根据自身项目来
  14. const userStore = useUserStore()
  15. // 全局添加请求头
  16. let obj = {
  17. // 获取Store中的token || 获取本地存储的token
  18. 'Authori-zation': (userStore.token || storage.getData("TOKEN") || ""),
  19. }
  20. if (header) {
  21. // 有无传入header,有则合并
  22. let headers = Object.assign(header, obj);
  23. header = headers;
  24. } else {
  25. header = obj
  26. }
  27. if (data) {
  28. // 清除无用参数
  29. Object.keys(data).forEach(key => {
  30. if (data[key] == null || data[key] == undefined || data[key] === '') {
  31. delete (data[key]);
  32. }
  33. })
  34. }
  35. return new Promise((resolve, reject) => {
  36. uni.request({
  37. url: apiUrl,
  38. method: type,
  39. data,
  40. header,
  41. success(res) {
  42. if (res.statusCode == 200) {
  43. const data: any = res.data;
  44. if (data.code == 0) {
  45. // 正常抛出数据
  46. resolve(data.data as T)
  47. } else {
  48. if(data.code == 401) {
  49. // 未登录
  50. uni.redirectTo({
  51. url: "" //未登录跳转指定页面
  52. })
  53. uni.hideLoading();
  54. return reject(data);
  55. }
  56. // 错误数据
  57. uni.hideLoading();
  58. // 弹窗错误框,这里是自己封装组件,
  59. common.toastErr(data.message || "网络请求异常")
  60. reject(data);
  61. }
  62. } else {
  63. console.log(data)
  64. uni.hideLoading();
  65. common.toastErr("网络请求异常")
  66. reject(data)
  67. }
  68. },
  69. fail(err) {
  70. console.log(err)
  71. uni.hideLoading();
  72. common.toastErr("网络请求异常")
  73. reject(err)
  74. }
  75. })
  76. })
  77. }

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

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

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

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

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

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

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

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

  1. export interface IConfig {
  2. // 接口主地址
  3. base: string;
  4. // 环境模式
  5. mode: string;
  6. // 地图key
  7. mapKey: string;
  8. // 密钥
  9. secretKey: string;
  10. }

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

  1. // dev 开发环境
  2. import {IConfig} from "../types";
  3. const test: IConfig = {
  4. // #ifdef H5
  5. base: "",
  6. // #endif
  7. // #ifdef MP-WEIXIN
  8. base:'http://192.168.1.15:8090/api',
  9. // #endif
  10. // 模式
  11. mode: "dev",
  12. // 地图key
  13. mapKey: "",
  14. // Secret Key
  15. secretKey: ""
  16. }
  17. export default test;

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

  1. // test 测试环境
  2. import {IConfig} from "../types";
  3. const test: IConfig = {
  4. // #ifdef H5
  5. base: "",
  6. // #endif
  7. // #ifdef MP-WEIXIN
  8. base:'http://192.168.1.15:8090/api',
  9. // #endif
  10. // 模式
  11. mode: "test",
  12. // 地图key
  13. mapKey: "",
  14. // Secret Key
  15. secretKey: ""
  16. }
  17. export default test;

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

  1. // prod 生产环境
  2. import {IConfig} from "../types";
  3. const test: IConfig = {
  4. // #ifdef H5
  5. base: "",
  6. // #endif
  7. // #ifdef MP-WEIXIN
  8. base:'http://www.baidu.com/api',
  9. // #endif
  10. // 模式
  11. mode: "prod",
  12. // 地图key
  13. mapKey: "",
  14. // Secret Key
  15. secretKey: ""
  16. }
  17. 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 内容如下: 

  1. import { IConfig } from "./types";
  2. import prod from "./prod";
  3. import test from "./test";
  4. import dev from "./dev";
  5. let obj: IConfig;
  6. // #ifdef MP-WEIXIN
  7. const plat = uni.getAccountInfoSync().miniProgram.envVersion
  8. if(plat === "release") {
  9. obj = prod
  10. } else if(plat === "trial") {
  11. obj = test
  12. } else {
  13. obj = dev
  14. }
  15. // #endif
  16. // #ifdef H5
  17. if(import.meta.env.MODE === "production") {
  18. obj = prod
  19. } else if(import.meta.env.MODE === "test") {
  20. obj = test
  21. } else {
  22. obj = dev
  23. }
  24. // #endif
  25. export default obj;

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

三.封装请求方式

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

  1. /**
  2. * http get 请求
  3. * @param url 请求接口
  4. * @param data 请求参数
  5. * @returns
  6. */
  7. const get = <T = any>(
  8. url: string,
  9. data: AnyObject
  10. ): Promise<T> => {
  11. return request(url, 'GET', data, {})
  12. }
  13. /**
  14. * http post json请求
  15. * @param url 请求接口
  16. * @param data 请求参数
  17. * @returns
  18. */
  19. const postJ = <T = any>(
  20. url: string,
  21. data: AnyObject
  22. ): Promise<T> => {
  23. return request(url, 'POST', data, {
  24. 'Content-Type': 'application/json'
  25. })
  26. }
  27. /**
  28. * http post form表单请求
  29. * @param url 请求接口
  30. * @param data 请求参数
  31. * @returns
  32. */
  33. const postW = <T = any>(
  34. url: string,
  35. data: AnyObject
  36. ): Promise<T> => {
  37. return request(url, 'POST', data, {
  38. 'Content-Type': 'application/x-www-form-urlencoded'
  39. })
  40. }
  41. /**
  42. * http put json请求
  43. * @param url 请求接口
  44. * @param data 请求参数
  45. * @returns
  46. */
  47. const putJ = <T = any>(url: string, data: AnyObject): Promise<T> => {
  48. return request(url, 'PUT', data, {
  49. 'Content-Type': 'application/json'
  50. })
  51. }
  52. /**
  53. * http put form表单请求
  54. * @param url 请求接口
  55. * @param data 请求参数
  56. * @returns
  57. */
  58. const putW = <T = any>(url: string, data: AnyObject): Promise<T> => {
  59. return request(url, 'PUT', data, {
  60. 'Content-Type': 'application/x-www-form-urlencoded'
  61. })
  62. }
  63. /**
  64. * http delete请求
  65. * @param url 请求接口
  66. * @param data 请求参数
  67. * @returns
  68. */
  69. const del = <T = any>(url: string, data: AnyObject): Promise<T> => {
  70. return request(url, 'DELETE', data, {})
  71. }
  72. export default {
  73. get,
  74. postJ,
  75. postW,
  76. putJ,
  77. putW,
  78. del
  79. }

四.调用请求

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

  1. //引入封装方法
  2. import http from "@/request";
  3. export const getTest = () => http.get<any>(`url`, {})
  4. export const postTest = (data:any) => http.postJ<any>(`url`, data)

总结 

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/325641
推荐阅读
相关标签
  

闽ICP备14008679号