持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
前言:对于程序员来说,同样的代码写两遍那就要考虑封装问题了,不是要求,就是懒不想复制,,在微信小程序开发过程中请求,封装wx.request必不可少,废话不多看代码
配置请求头
请求头里面放一些后端要求的参数,比如这里有app-type,因为牵扯到多个端,以及便于后台数据统计,后端需要一个参数进行区分请求来源,然后就是token判断是否登录的标识
// 请求头
let headers = {
"content-type": "application/json",
"app-type": "wxapp",//后端要求的
"version": version,//版本号
};
if (wx.getStorageSync('wx_token')) {
headers.token = wx.getStorageSync('wx_token')
}
请求的配置对象,请求的路径,header,请求方式
//请求对象
let requestObj = {
url: config.Config.path + url,
header: headers,
method: type,
};
请求数据data
请求携带的数据data,根据请求方式POST和PUT,单独做处理,合并到请求的配置对象中
if (type == 'POST') {
Object.assign(requestObj, {
data: postData
})
} else if (type == 'PUT') {
Object.assign(requestObj, {
data: JSON.stringify(putData)
})
}
请求完成回调函数
然后就是处理请求之后返回的回调函数,并且合并到请求的配置对象中。
success:处理请求成功success函数,根据后端给的返回码标注,进行不同处理。
状态100开头的指定几个返回码跟token有关,10005代表账号注销跳转登录;
返回码400开头的是用于给用户提示,直接调用showToast弹出提示;
返回码1,0,5根据实时情况进行处理,这边因为是提前封装,没有针对性做处理,直接执行success函数
fail:请求失败的函数,统一做提示处理,并且打印返回的内容便于查看
complete:请求完成,无论成功失败都会处理,这里是做了一个多请求的处理,稍后再讲;
Object.assign(requestObj, {
success: function (res) {
//参数值为res.data,直接将返回的数据传入
if (res.data.new_token) {
wx.setStorageSync('wx_token', res.data.new_token)
}
let status = res.data.status;
// 1开头处理
let loginArr = [10001, 10002, 10003, 10004, 10005];
if (loginArr.includes(status)) {
let statusText = status == 10005 ? '账号已冻结(注销)' : '登录过期';
wx.showToast({
title: statusText,
icon: 'none',
duration: 1500,
success(res) {
navigateToLogin();
}
})
}
// 4开头处理
if (String(status).charAt(0) == 4) {
return wx.showToast({
title: res.data.message,
icon: 'none',
duration: 3000
})
}
// 返回1、0、5开头,调用请求成功函数
doSuccess(res.data);
console.log('success', res);
},
fail: function (error) {
console.log('error', error);
if (doFail) doFail(error);
wx.showToast({
title: '网络繁忙',
icon: 'none',
duration: 3000
})
},
complete: info => {
if (doComplete) doComplete(info);
if (reqOption.moreRequest) {
reduceLoadingCount()
} else {
wx.hideLoading()
}
}
})
封装request
此时所有请求的配置对象处理完毕,然后将配置对象放入wx.request中,并且声明一个函数request用于存放请求,和配置对象;
函数request参数描述
type:请求类型
url:请求地址
postData:请求参数
doSuccess:请求成功回调
doFail:请求失败回调
doComplete:请求完成回调
reqOption:配置对象{moreRequest:true,closeLoading:true}
多请求并发,以及多请求按顺序执行的loading多次弹出问题
配置对象描述:
moreRequest:布尔值,是否为多请求 closeLoading:布尔值,请求是否显示loading
closeLoading参数是为了当多个请求不是并发,且存在执行顺序关系,也会有连续多个弹窗关闭显现的问题,这时候可以使用closeLoading参数,设置为true,除了第一个执行的函数之外其余函数配置closeLoading为true,然后在最后一个函数执行的complete里面进行关闭loading,这样就达到了多个函数按照顺序执行且loading多次关闭显现的问题了。
moreRequest参数是为了解决多个请求并发,不存在执行顺序。每次调用request判断一下moreRequest的值如果存在执行addLoadingCount增加计数,在complete里面执行reduceLoadingCount减少计数,当计数为0时reduceLoadingCount里面执行wx.hideLoading()关闭弹窗 这样就解决了多请求同时并发时的弹窗多次弹出关闭问题
function request(type, url, postData, doSuccess, doFail, doComplete, reqOption) {
// 判断是否是多请求,是都开启loading计数
if (reqOption.moreRequest) {
addLoadingCount
} else {
if (loadingCount != 0) {
loadingCount = 0;
}
}
// 判断是否关闭loading
if(!reqOption.closeLoading){
wx.showLoading({
title: '加载中...',
mask: true
})
}
let requestObj = {}//配置对象
wx.request(requestObj)
};
// loading计数
let loadingCount = 0;
// 增加请求计数
function addLoadingCount() {
loadingCount++;
}
//减少请求计数
function reduceLoadingCount() {
loadingCount--;
if (loadingCount < 1) {
wx.hideLoading()
}
}
以上就是封装的请求,reqOption的用配置放在了最后一位,需要单独进行判断,最后一位有可能是函数,有可能是配置多请求或者关闭loading的对象,所以我们需要写一个函数用于处理请求的参数,当为GET,DELETE请求时是没有单独的请求data,以及如果只需要某个回调函数,需要我们进行判断然后赋空值占位,以免干扰请求时的判断
// 处理请求参数
function formatRequestParams(reqParams, type) {
// 参数数组
let paramsArr = [];
for (let i = 0; i < reqParams.length; i++) {
paramsArr[i] = reqParams[i]
}
//'GET', 'DELETE',无请求参数赋值为空
if (['GET', 'DELETE'].includes(type)) {
paramsArr.splice(1, 0, '')
}
if (paramsArr.length < 6) {
// 计算参数位数差值,填补空值
let diffArr = [];
for (let i = 0; i < 6 - paramsArr.length; i++) {
diffArr.push('');
}
console.log(utils.judgeDataType(paramsArr[paramsArr.length - 1]));
if (utils.judgeDataType(paramsArr[paramsArr.length - 1]) == 'object' && JSON.stringify([paramsArr.length - 1]) != '{}') {
paramsArr = paramsArr.slice(0, paramsArr.length - 1).concat(diffArr).concat(paramsArr.slice(paramsArr.length - 1))
} else {
paramsArr = paramsArr.concat(diffArr)
}
}
return paramsArr;
};
函数调用
// POST请求:参数顺序url, postData, doSuccess, doFail, doComplete, reqOption
function postReq() {
let paramsArr = ['POST'].concat(formatRequestParams(arguments, 'POST'));
console.log('请求之后', paramsArr);
request(...paramsArr)
}
// GET请求: 参数顺序 url, doSuccess, doFail,doComplete, reqOption
function getReq() {
let paramsArr = ['GET'].concat(formatRequestParams(arguments, 'GET'));
console.log('请求之后', paramsArr);
request(...paramsArr)
}
// PUT请求:参数顺序url, postData, doSuccess, doFail, doComplete, reqOption
function putReq() {
let paramsArr = ['PUT'].concat(formatRequestParams(arguments, 'PUT'));
request(...paramsArr)
}
// DELETE请求:参数顺序 url, doSuccess, doFail,doComplete, reqOption
function deleteReq() {
let paramsArr = ['DELETE'].concat(formatRequestParams(arguments, 'DELETE'));
request(...paramsArr)
}
module.exports = {
postReq, //post请求
getReq, //get请求
putReq, //put请求
deleteReq //delete请求
}
如果需要进行网络判断可以封装一个判断网络状态的函数,将请求的函数放入判断网络状态的会调用,无网络给予提示
完整代码如下
var config = require('./config')
var utils = require('./util')
var app = getApp();
// 版本号
var version = config.Config.version
// loading计数
let loadingCount = 0;
// 增加请求计数
function addLoadingCount() {
loadingCount++;
}
//减少请求计数
function reduceLoadingCount() {
loadingCount--;
if (loadingCount < 1) {
wx.hideLoading()
}
}
// 跳转登录
function navigateToLogin() {
let inLogin = app.globalData.inLogin; //判断当前页面是否在登录页面
if (!inLogin) {
app.globalData.inLogin = true;
wx.clearStorageSync()
wx.navigateTo({
url: '/pages/login/login',
})
}
};
/*
请求字段描述:
type:请求类型
url:请求地址
postData:请求参数
doSuccess:请求成功回调
doFail:请求失败回调
doComplete:请求完成回调
reqOption:配置对象{moreRequest:true,closeLoading:true}
配置对象描述:
moreRequest:布尔值,是否为多请求 closeLoading:布尔值,请求是否显示loading
*/
function request(type, url, postData, doSuccess, doFail, doComplete, reqOption) {
// 判断是否是多请求,是都开启loading计数
if (reqOption.moreRequest) {
addLoadingCount
} else {
if (loadingCount != 0) {
loadingCount = 0;
}
}
// 判断是否关闭loading
if(!reqOption.closeLoading){
wx.showLoading({
title: '加载中...',
mask: true
})
}
// 请求头
let headers = {
"content-type": "application/json",
"app-type": "wxapp",
"version": version,
}
if (wx.getStorageSync('wx_token')) {
headers.token = wx.getStorageSync('wx_token')
}
//请求对象
let requestObj = {
url: config.Config.path + url,
header: headers,
method: type,
};
if (type == 'POST') {
Object.assign(requestObj, {
data: postData
})
} else if (type == 'PUT') {
Object.assign(requestObj, {
data: JSON.stringify(putData)
})
}
// 合并 请求参数和请求返回函数
Object.assign(requestObj, {
success: function (res) {
//参数值为res.data,直接将返回的数据传入
if (res.data.new_token) {
wx.setStorageSync('wx_token', res.data.new_token)
}
let status = res.data.status;
// 1开头处理
let loginArr = [10001, 10002, 10003, 10004, 10005];
if (loginArr.includes(status)) {
let statusText = status == 10005 ? '账号已冻结(注销)' : '登录过期';
wx.showToast({
title: statusText,
icon: 'none',
duration: 1500,
success(res) {
navigateToLogin();
}
})
}
// 4开头处理
if (String(status).charAt(0) == 4) {
return wx.showToast({
title: res.data.message,
icon: 'none',
duration: 3000
})
}
// 返回1、0、5开头,调用请求成功函数
doSuccess(res.data);
console.log('success', res);
},
fail: function (error) {
console.log('error', error);
if (doFail) doFail(error);
wx.showToast({
title: '网络繁忙',
icon: 'none',
duration: 3000
})
},
complete: info => {
if (doComplete) doComplete(info);
if (reqOption.moreRequest) {
reduceLoadingCount()
} else {
wx.hideLoading()
}
}
})
wx.request(requestObj)
}
// 处理请求参数
function formatRequestParams(reqParams, type) {
// 参数数组
let paramsArr = [];
for (let i = 0; i < reqParams.length; i++) {
paramsArr[i] = reqParams[i]
}
//'GET', 'DELETE',无请求参数赋值为空
if (['GET', 'DELETE'].includes(type)) {
paramsArr.splice(1, 0, '')
}
if (paramsArr.length < 6) {
// 计算参数位数差值,填补空值
let diffArr = [];
for (let i = 0; i < 6 - paramsArr.length; i++) {
diffArr.push('');
}
console.log(utils.judgeDataType(paramsArr[paramsArr.length - 1]));
if (utils.judgeDataType(paramsArr[paramsArr.length - 1]) == 'object' && JSON.stringify([paramsArr.length - 1]) != '{}') {
paramsArr = paramsArr.slice(0, paramsArr.length - 1).concat(diffArr).concat(paramsArr.slice(paramsArr.length - 1))
} else {
paramsArr = paramsArr.concat(diffArr)
}
}
return paramsArr;
};
// POST请求:参数顺序url, postData, doSuccess, doFail, doComplete, reqOption
function postReq() {
let paramsArr = ['POST'].concat(formatRequestParams(arguments, 'POST'));
console.log('请求之后', paramsArr);
request(...paramsArr)
}
// GET请求: 参数顺序 url, doSuccess, doFail,doComplete, reqOption
function getReq() {
let paramsArr = ['GET'].concat(formatRequestParams(arguments, 'GET'));
console.log('请求之后', paramsArr);
request(...paramsArr)
}
// PUT请求:参数顺序url, postData, doSuccess, doFail, doComplete, reqOption
function putReq() {
let paramsArr = ['PUT'].concat(formatRequestParams(arguments, 'PUT'));
request(...paramsArr)
}
// DELETE请求:参数顺序 url, doSuccess, doFail,doComplete, reqOption
function deleteReq() {
let paramsArr = ['DELETE'].concat(formatRequestParams(arguments, 'DELETE'));
request(...paramsArr)
}
module.exports = {
postReq, //post请求
getReq, //get请求
putReq, //put请求
deleteReq //delete请求
}