開始
對(duì)于創(chuàng)維俱樂部2019-2020完成的小程序,進(jìn)行總結(jié),主要講解解決實(shí)際問題的過程以及思路。
努力對(duì)代碼進(jìn)行高度封裝,保證小程序運(yùn)行狀態(tài)監(jiān)控,與后臺(tái)交互能夠流暢,使得運(yùn)行邏輯清晰。
httprequest
雖然小程序本身對(duì)請求有了wx.request()的封裝,但我們在項(xiàng)目開發(fā)過程中還是對(duì)其進(jìn)行了二次封裝,根據(jù)后臺(tái)接口文檔,把部分功能進(jìn)行統(tǒng)一的封裝,努力實(shí)現(xiàn)接口可擴(kuò)展性強(qiáng),對(duì)請求的業(yè)務(wù)分離清晰,保證小程序請求過程能夠完整監(jiān)聽,避免網(wǎng)絡(luò)不暢通,多次點(diǎn)擊造成堵塞等。
首先,根據(jù)需要請求不同的數(shù)據(jù)類型,并且需要加入鑒權(quán)的sessionId封裝出一個(gè)httprequest
import getSessionId from '../API/getSessionId'
const baseUrl = require('../config/index').baseUrl // 服務(wù)器基址
const paramSession = [{},// 選擇不同的header
{'content-type': 'application/json' // 不帶上session發(fā)送請求
},
{'content-type': 'application/x-www-form-urlencoded', // 當(dāng)發(fā)送的參數(shù)要求為int時(shí)使用
},
{'content-type': 'application/x-www-form-urlencoded;charset=utf-8',
},
{'content-type': 'application/json', // 當(dāng)請求需要帶上登錄狀態(tài)時(shí)使用
},
{'content-type': 'multipart/form-data; boundary=XXX', // 上傳文件時(shí)使用
}];
/**
*
* @param {*} loading 請求大型數(shù)據(jù)包標(biāo)志
* @param {*} url 請求地址
* @param {*} sessionChoose 根據(jù)數(shù)據(jù)類型選擇content-type
* @param {*} sessionId 鑒權(quán)的sessionId
* @param {*} params 發(fā)送的數(shù)據(jù)
* @param {*} method 請求方法
* @param {*} authCheck 是否需要鑒權(quán)的標(biāo)志
*/
function httpRequest(loading, url, sessionChoose, sessionId, params, method,authCheck=true) { // 封裝統(tǒng)一的請求方法
if (loading == true) { // 加載提示
wx.showToast({
title: '數(shù)據(jù)加載中',
icon: 'loading'
})
};
const realDeal=function() { // 實(shí)際處理的請求內(nèi)容
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狀態(tài)有誤
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"]) // 不為空時(shí)更新sessionId
}
resolve(res);
},
fail: err => {
console.log(err)
if (loading == true) {
wx.hideToast()
}
reject(err);
},
complete: () => {}
})
})
};
const httpReal=realDeal(); // 實(shí)際處理請求內(nèi)容的promise
if(authCheck){ // 需要登錄狀態(tài)
if(getSessionId()){
return httpReal
}else{
wx.showToast({
title: '請先登錄',
duration: 2000
});
return
}
}else{ // 公共接口,不需登錄
return httpReal
}
}
export default httpRequest
檢測登錄狀態(tài)
由于我們把sessionId儲(chǔ)存在了小程序本地緩存中,那就有可能會(huì)造成一種情況:后臺(tái)的登錄信息已經(jīng)過期,但是本地緩存依然存著sessionId,所有需要鑒權(quán)的請求都無法成功。
于是,我們可以封裝一個(gè)檢測sessionId是否過期的方法,若已經(jīng)過期,則清空相關(guān)緩存,提醒用戶需要進(jìn)行登錄。
import httpRequest from '../utils/httpRequest'
function myCheckSession(callback1,callback2){ // callback2是不存在sessionId時(shí)直接運(yùn)行的回調(diào)函數(shù),可選
let _sessionId = wx.getStorageSync('sessionId')
let url = '/api/user/showFav/1' // 測試是否sessionId是否仍有效(登錄狀態(tài)有效)
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時(shí)必須先執(zhí)行該函數(shù),剩余部分放在回調(diào)函數(shù)中
})
}
else{
wx.setStorageSync('state', 0)
if(callback2){ // 令callback2可選
callback2() // 未登錄時(shí)直接運(yùn)行(sessionId不存在)
}
}
};
export default myCheckSession
接著,我們需要一個(gè)動(dòng)態(tài)獲取sessionId的方法,當(dāng)我們的請求需要鑒權(quán)的時(shí)候,就從本地緩存中取出來加到報(bào)文表頭。但是,在加入報(bào)文之前,還需要通過上方的方法鑒別sessionId是否已經(jīng)過期。為了避免頁面加載時(shí)多個(gè)請求同時(shí)獲取sessionId,導(dǎo)致引起多次鑒別sessionId是否過期,我們需要通過一個(gè)本地變量記錄查詢情況。
import myCheckSession from './myCheckSession'
let isGettingId=false
function getSessionId(){
try{
if(!isGettingId){ // 避免多次獲取
myCheckSession(function(){
let state = wx.getStorageSync('state') // 登錄狀態(tài),是否過期
isGettingId=true;
if(state){
return wx.getStorageSync('sessionId')
}else{ // 登錄過期
return false
}
})
}
}catch(err){
console.log(err);
return Promise.reject(err)
}
}
export default getSessionId
本項(xiàng)目中,我們運(yùn)用了我們自已的登錄系統(tǒng),但更好的是后臺(tái)能夠調(diào)用微信官方的登錄鑒權(quán),對(duì)其進(jìn)行封裝,獲取到我們需要的信息。在以后的項(xiàng)目開發(fā)中應(yīng)該修改這項(xiàng)標(biāo)準(zhǔn)。
cloudData
由于一些原因,后面嘗試把部分接口分離到了云開發(fā)模式,我們對(duì)云數(shù)據(jù)庫的操作進(jìn)行了簡單的封裝,如下:
const DB=wx.cloud.database()
const _=DB.command;
// 連接collection并封裝增刪改查操作
class Collection{
constructor(name){
this.collection=DB.collection(name);
}
add(data){ // 增加一條數(shù)據(jù)
return this.collection.add({
data
}) // 返回promise
}
get(where){ // 獲取滿足條件的數(shù)據(jù)
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,
_
}
以上封裝還不完善,以后可以再探索。
項(xiàng)目中,對(duì)于請求基礎(chǔ)的封裝如上,第一篇總結(jié)就先介紹這些。