微信小程序封装请求API-promise格式

微信小程序原生的请求API就是wx.request

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

有时候不能很好的适配我们的开发需求,比如我们要加一些基础url路径、请求前后的loading效果、不同接口名称下的header。而且,在success回调方法里写请求成功后的操作,看起来代码不太清晰。接下来讲一下封装的逻辑,完整代码放在最后。

第一步:在app.js同级目录下,创建一个文件夹

在utils文件夹里新建一个service.js文件,用来放封装的wx.request方法

第二步:封装wx.request方法成promise对象

使用promise对象能很好的解决回调地狱,在.then(res=>{}).catch(err=>{})中能很清晰地看出代码的逻辑

c 复制代码
export const request = (parmas) => {
    // 返回一个promise对象
    return new Promise((resolve, reject) => {
        wx.request({
            url: parmas.url, //仅为示例,并非真实的接口地址
            data:parmas.data,
            header: {
                'content-type': 'application/json' // 默认值
            },
            success: (res)=> {
                 // 请求成功,就将成功的数据返回出去
                resolve(result)
            },
            fail: (err) => {
                reject(err)
            },
        })
    })
}

注意:success: (result) => {} 使用箭头函数,防止出现this指向错误

这样,就算是封装了一个最简单、最基础(简陋)的请求API了,在需要使用这个方法的页面的js文件中,引入它

第三步:页面中引用封装的请求API

页面

c 复制代码
/**
 * 小程序中要引用方法,哪个页面要用,就在哪个页面引入
 */
import { request } from "../../utils/service";
Page({
  /**
   * 页面的初始数据
   */
  data: { 
  ..........
  ..........
 
 getGoodsList () {
    //因为返回的是promise对象,所以通过.then来获取resolve出来的请求成功的返回数据
    request({ url: "https://xxxtest/goods/search", data: this.QueryParams })
      .then((res) => {
        console.log(res);
    })
  }

现在,来详细扩展一下封装的请求API

1.设置基础请求路径

c 复制代码
// 基础url
const baseUrl = "https://xxxtest"

这样,就可以简化调用这个方法时url的参数内容了,也方便统一修改开发环境地址、生产环境地址

c 复制代码
// url: "/goods/list" ==》  url中不用再写前面的一长串了
export function getGoodsList(params) {
  return request({
    url: `/goods/list`,
    method: 'POST',
    params
  })
}

2.解构传入的参数

我们可以通过ES6中的扩展运算符,将传入到封装方法里的参数直接全部解构出来,不用再一个个获取赋值给对应的键值对了 ...parmas 直接解构出传入的参数

c 复制代码
export const request = (parmas) => {
    //设置基础请求头
    const baseUrl = "https://xxxtest"
    // 返回一个promise对象
    return new Promise((resolve, reject) => {
        /**
             *  ...parmas ===>就是将传进来的参数扩展开,一行行展示在这里面
             * 比如:传进来
             * {
             *  url:'xx',
             *  data:{key1:val1,key2:val2}
             * }
             * 那么通过  ...parmas  就会把这些内容展示到这里了
        */
        wx.request({
            ...parmas,
            // 注意,此行必须放在   ...parmas之下,才能覆盖其解构出的,传入的url:xxx参数
            url: baseUrl + parmas.url,
            success: (res)=> {
                 // 请求成功,就将成功的数据返回出去
                resolve(result)
            },
            fail: (err) => {
                reject(err)
            },
        })
    })
}

3.根据不同的url接口添加不同的header

header中的Authorization字段一般存储token,用来做身份验证,但有些请求不需要携带token,所以这个封装的API中需要能根据传入的url来判断什么时候该给请求添加上token,什么时候不用可以添加。

c 复制代码
export const request = (parmas) => {
/**
 *   根据不同的url接口,来设置不同的header请求头
 **  判断 url中是否带有 /my/ 请求的是私有的路径 带上header token
 **  { ...parmas.header }  ==> 先解构出传进来的header对象,然后再往这个对象里面添加Authorization字段数据,这样即使有传入header的其他字段也能保留下来
 *   如果传入的parmas参数中没有header,那myHeader就是个空的对象 {} 因为啥都没有
 */
let myHeader = { ...parmas.header };
//通过includes方法查找字符串中是否包含指定内容,进而判断是否要添加token
if (parmas.url.includes("/neddToken/")) {
    // 往myHeader这个对象里插入键值对 带上Storage中存储的token
    myHeader["Authorization"] = wx.getStorageSync("token");
}

//设置基础请求头
const baseUrl = "https://xxxtest"
// 返回一个promise对象
return new Promise((resolve, reject) => {
    wx.request({
        ...parmas,
        url: baseUrl + parmas.url,
        /**
         * !可以设置上默认的content-type,然后再扩展出传入的myHeader,如果传入的myHeader为空,那header就还是默认的content-type一个键值对
         * !{ 'content-type': 'application/json', ...myHeader } ==》 扩展出myHeader这 个对象中的键值对;
         */
        header: { 'content-type': 'application/json', ...myHeader },
        success: (res)=> {
             // 请求成功,就将成功的数据返回出去
            resolve(result)
        },
        fail: (err) => {
            reject(err)
        },
    })
})
}

此时,在使用这个封装的API的时候,就可以对header进行设置了,例如:

c 复制代码
request({
  url: '/neddToken/home/swiperdata',
  // 使用的时候也可以传入一些header的字段
  header: {
    'content-type': 'application/json',
    'Date': 'Tue, 15 Nov 2021 08:12:31 GMT'
  },
  method: 'GET',
}).then((result) => {
   console.log(result)
})

此时,因为请求url中含有【neddToken】,就会在header中插入token

4.添加请求发起时页面loading效果

当页面在加载数据的时候,最好要有一个loading的提示,同时有遮罩,防止用户乱点

所以,就需要在封装的API中加入微信小程序的wx.showLoading遮罩层了

c 复制代码
    // 显示加载中loading效果
    wx.showLoading({
        title: "加载中",
        mask: true  //开启蒙版遮罩
    });
    ...
    ...
    //  关闭正在等待loading效果
    wx.hideLoading();

如果直接在封装的API的开始加上loading,在请求结束加上隐藏loading效果,那乍看一下,好像没错,但是如果一个页面同时触发了多个请求呢?比如打开一个页面,同时加载多个模块,需要从不同的接口请求数据,那就会使用多次这个封装的API。

此时,就会出现,第一个请求结束,直接关闭了loading效果,而后面几个请求就没有loading效果的遮罩了。

所以,需要在封装的js文件中设置一个全局变量,每次调用这个封装的文件时,就对这个变量++,每次请求结束,返回数据出去的时候,就对这个变量--,最后判断一下这个变量是否为0(也就是所有请求的结束了),在决定是否关闭loading效果

c 复制代码
let ajaxTimes = 0
export  const request = (params)=>{
	//有调用的时候增加全局变量,用于判断有几个请求
	ajaxTimes++
	wx.showLoading({
        title: "加载中",
        mask: true  //开启蒙版遮罩
    });
}
c 复制代码
complete:()=>{
	//每次请求结束后就减少全局变量,当为0时,就表示这是最后一个请求了
	ajaxTimes--
	if(ajaxTimes ==0) {
		wx.hideLoading();
	}
}

完整的封装请求API的js文件

c 复制代码
// 同时发送异步代码的次数
let ajaxTimes = 0;
export const request = (parmas) => {
    // 当有地方调用请求方法的时候,就增加全局变量,用于判断有几个请求了
    ajaxTimes++;
    // 显示加载中loading效果
    wx.showLoading({
        title: "加载中",
        mask: true  //开启蒙版遮罩
    });
    let myHeader = { ...parmas.header };
    if (parmas.url.includes("/neddToken/")) {
        // 往myHeader这个对象里插入键值对 带上Storage中存储的token
        myHeader["Authorization"] = wx.getStorageSync("token");
    }
    // 基础url
    const baseUrl = "https://xxxtest"
    return new Promise((resolve, reject) => {
        wx.request({
            ...parmas,
            url: baseUrl + parmas.url,
            header: { 'content-type': 'application/json', ...myHeader },
            success: (result) => {
                // 请求成功,就将成功的数据返回出去
                resolve(result)
            },
            fail: (err) => {
                reject(err)
            },
            // 不管请求成功还是失败,都会触发
            complete: () => {
                ajaxTimes--;
                // 此时就可以关闭loading效果了
                if (ajaxTimes === 0) {
                    //  关闭正在等待loading效果
                    wx.hideLoading();
                }
            }
        });
 
    })
}
 

进一步完善封装请求

如果一个接口在多个页面中都需求,那么直接在页面引入请求会比较麻烦,不利于后期维护,可以把请求放在单独的文件里来统一维护。

在api文件夹下创建一个index.js文件,用来存放项目中的接口请求

index.js文件

import request from '@/utils/service'

// 获取商品信息
export function getGoodsList(params) {
  return request({
    url: `https://xxxtest/goods/list`,
    method: 'POST',
    params
  })
}

页面

c 复制代码
/**
 * 小程序中要引用方法,哪个页面要用,就在哪个页面引入
 */
import { api } from "../../api/index";
Page({
  /**
   * 页面的初始数据
   */
  data: { 
  ..........
  ..........
 
 getGoodsList () {
    //因为返回的是promise对象,所以通过.then来获取resolve出来的请求成功的返回数据
    api.getGoodsList({ data: this.QueryParams })
      .then((res) => {
        console.log(res);
    })
  }
相关推荐
长风清留扬2 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
郭wes代码12 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
.生产的驴17 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
汤姆yu1 天前
基于微信小程序的乡村旅游系统
微信小程序·旅游·乡村旅游
计算机徐师兄1 天前
基于TP5框架的家具购物小程序的设计与实现【附源码、文档】
小程序·php·家具购物小程序·家具购物微信小程序·家具购物
曲辒净1 天前
微信小程序实现二维码海报保存分享功能
微信小程序·小程序
朽木成才1 天前
小程序快速实现大模型聊天机器人
小程序·机器人
peachSoda71 天前
随手记:小程序使用uni.createVideoContext视频无法触发播放
小程序
何极光1 天前
uniapp小程序样式穿透
前端·小程序·uni-app
小墨&晓末1 天前
【PythonGui实战】自动摇号小程序
python·算法·小程序·系统安全