微信小程序原生的请求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);
})
}