开始
对于创维俱乐部2019-2020完成的小程序,进行总结,主要讲解解决实际问题的过程以及思路。
努力对代码进行高度封装,保证小程序运行状态监控,与后台交互能够流畅,使得运行逻辑清晰。
httprequest
虽然小程序本身对请求有了wx.request()
的封装,但我们在项目开发过程中还是对其进行了二次封装,根据后台接口文档,把部分功能进行统一的封装,努力实现接口可扩展性强,对请求的业务分离清晰,保证小程序请求过程能够完整监听,避免网络不畅通,多次点击造成堵塞等。
首先,根据需要请求不同的数据类型,并且需要加入鉴权的sessionId封装出一个httprequest
import getSessionId from '../API/getSessionId'
const baseUrl = require('../config/index').baseUrl // 服务器基址
const paramSession = [{},// 选择不同的header
{'content-type': 'application/json' // 不带上session发送请求
},
{'content-type': 'application/x-www-form-urlencoded', // 当发送的参数要求为int时使用
},
{'content-type': 'application/x-www-form-urlencoded;charset=utf-8',
},
{'content-type': 'application/json', // 当请求需要带上登录状态时使用
},
{'content-type': 'multipart/form-data; boundary=XXX', // 上传文件时使用
}];
/**
*
* @param {*} loading 请求大型数据包标志
* @param {*} url 请求地址
* @param {*} sessionChoose 根据数据类型选择content-type
* @param {*} sessionId 鉴权的sessionId
* @param {*} params 发送的数据
* @param {*} method 请求方法
* @param {*} authCheck 是否需要鉴权的标志
*/
function httpRequest(loading, url, sessionChoose, sessionId, params, method,authCheck=true) { // 封装统一的请求方法
if (loading == true) { // 加载提示
wx.showToast({
title: '数据加载中',
icon: 'loading'
})
};
const realDeal=function() { // 实际处理的请求内容
return new Promise((resolve,reject) => {
wx.request({
url: baseUrl + url,
data: params,
dataType: "json",
header: Object.assign(paramSession[sessionChoose],{'Cookie':sessionId||wx.getStorageSync("sessionId")}),
method: method,
success: res => {
console.log(res)
if (loading == true) {
wx.hideToast()
};
const status=res.statusCode
const isHttpSuccess=status>=200&&status<300||status===304;
if(!isHttpSuccess){ // 返回status状态有误
reject({
msg:`httpstatus error: ${status}`,
detail:res
});
return
}
var cookie = res.header["Set-Cookie"] // 获取返回得到的sessionId
if (cookie != null) {
wx.setStorageSync("sessionId", res.header["Set-Cookie"]) // 不为空时更新sessionId
}
resolve(res);
},
fail: err => {
console.log(err)
if (loading == true) {
wx.hideToast()
}
reject(err);
},
complete: () => {}
})
})
};
const httpReal=realDeal(); // 实际处理请求内容的promise
if(authCheck){ // 需要登录状态
if(getSessionId()){
return httpReal
}else{
wx.showToast({
title: '请先登录',
duration: 2000
});
return
}
}else{ // 公共接口,不需登录
return httpReal
}
}
export default httpRequest
检测登录状态
由于我们把sessionId储存在了小程序本地缓存中,那就有可能会造成一种情况:后台的登录信息已经过期,但是本地缓存依然存着sessionId,所有需要鉴权的请求都无法成功。
于是,我们可以封装一个检测sessionId是否过期的方法,若已经过期,则清空相关缓存,提醒用户需要进行登录。
import httpRequest from '../utils/httpRequest'
function myCheckSession(callback1,callback2){ // callback2是不存在sessionId时直接运行的回调函数,可选
let _sessionId = wx.getStorageSync('sessionId')
let url = '/api/user/showFav/1' // 测试是否sessionId是否仍有效(登录状态有效)
if(_sessionId){
return httpRequest(false,url,4,_sessionId,null,'GET',false).then(res => {
if(res.statusCode == 200){
wx.setStorageSync('state', 1)
}
else{
wx.removeStorageSync('userInfo')
wx.removeStorageSync('sessionId')
wx.setStorageSync('state',0)
wx.showToast({
title: res.data.message,
icon: 'none'
})
}
})
.then(() =>{
callback1() // 保证在使用checksession时必须先执行该函数,剩余部分放在回调函数中
})
}
else{
wx.setStorageSync('state', 0)
if(callback2){ // 令callback2可选
callback2() // 未登录时直接运行(sessionId不存在)
}
}
};
export default myCheckSession
接着,我们需要一个动态获取sessionId的方法,当我们的请求需要鉴权的时候,就从本地缓存中取出来加到报文表头。但是,在加入报文之前,还需要通过上方的方法鉴别sessionId是否已经过期。为了避免页面加载时多个请求同时获取sessionId,导致引起多次鉴别sessionId是否过期,我们需要通过一个本地变量记录查询情况。
import myCheckSession from './myCheckSession'
let isGettingId=false
function getSessionId(){
try{
if(!isGettingId){ // 避免多次获取
myCheckSession(function(){
let state = wx.getStorageSync('state') // 登录状态,是否过期
isGettingId=true;
if(state){
return wx.getStorageSync('sessionId')
}else{ // 登录过期
return false
}
})
}
}catch(err){
console.log(err);
return Promise.reject(err)
}
}
export default getSessionId
本项目中,我们运用了我们自已的登录系统,但更好的是后台能够调用微信官方的登录鉴权,对其进行封装,获取到我们需要的信息。在以后的项目开发中应该修改这项标准。
cloudData
由于一些原因,后面尝试把部分接口分离到了云开发模式,我们对云数据库的操作进行了简单的封装,如下:
const DB=wx.cloud.database()
const _=DB.command;
// 连接collection并封装增删改查操作
class Collection{
constructor(name){
this.collection=DB.collection(name);
}
add(data){ // 增加一条数据
return this.collection.add({
data
}) // 返回promise
}
get(where){ // 获取满足条件的数据
return this.collection.where({
...where
}).get()
}
getlimit(skipIndex,limitIndex){
return this.collection.skip(skipIndex).limit(limitIndex).get()
}
update(where,data){
return this.collection.where({
...where
}).update({
data
})
}
remove(where){
return this.collection.where({
...where
}).remove()
}
}
module.exports={
Collection,
_
}
以上封装还不完善,以后可以再探索。
项目中,对于请求基础的封装如上,第一篇总结就先介绍这些。
网友评论