一、需求:
-
在發(fā)送請求之前,先判斷用戶是否有token,沒有就執(zhí)行登陸請求,將token保存,然后再執(zhí)行原來請求;
-
擁有token,就直接執(zhí)行請求;但是用戶的這個token可能是過期的,如果執(zhí)行請求發(fā)現(xiàn)用戶登陸過期,就統(tǒng)一返回40001,然后對40001的響應(yīng)統(tǒng)一處理,執(zhí)行登陸請求,再執(zhí)行原來請求。
-
最終實(shí)現(xiàn)用戶無感登陸的體驗(yàn)效果。
二、流程圖如下:
三、主要代碼
/**
* 請求攔截器:
* 在這里實(shí)現(xiàn)的作用是將所有請求前判斷用戶是否授權(quán)獲取用戶信息
* @param {*} config
*/
function requestInterceptor(config) {
console.log("經(jīng)過了請求攔截器")
return new Promise((resolve, reject) => {
if (!config.header.authorization) {
userLogin().then(res =>{
if(res){
config.header.authorization = wx.getStorageSync('userInfo').token
resolve(config);
}
})
} else {
resolve(config);
}
});
}
// 響應(yīng)攔截器
function responseInterceptor(response) {
console.log("經(jīng)過響應(yīng)攔截器")
return new Promise((resolve, reject) => {
// 處理響應(yīng)結(jié)果
if (response.data.flag) {
resolve(response);
} else {
if (response.data.code === 40001) {
userLogin().then(res => {
reject(response)
})
} else {
wx.showToast({
title: response.data.message,
icon: "error",
duration: 2000
})
}
}
});
}
其中封裝的一個post請求,帶請求頭
其他請求的封裝方法完成類似,懂一個其他就都懂了。
四、完整代碼:
var tokenKey = "userInfo"; // 將登陸憑證儲存以key為“token”儲存在本地
var serverUrl = "http://localhost:8088/wechat"; // 2020
// 例外不用token的地址
// var exceptionAddrArr = ['/user/login', ];
var exceptionAddrArr = [];
//請求頭處理函數(shù)
function CreateHeader(url, type) {
let header = {}
if (type == 'POST_PARAMS') {
header = {
'content-type': 'application/x-www-form-urlencoded'
}
} else {
header = {
'content-type': 'application/json'
}
}
if (exceptionAddrArr.indexOf(url) == -1) { //排除請求的地址不須要token的地址
let token = wx.getStorageSync(tokenKey).token;
// header.Authorization = token;
header['authorization'] = token;
}
return header;
}
/**
* 請求攔截器:
* 在這里實(shí)現(xiàn)的作用是將所有請求前判斷用戶是否授權(quán)獲取用戶信息
* @param {*} config
*/
function requestInterceptor(config) {
console.log("經(jīng)過了請求攔截器")
return new Promise((resolve, reject) => {
if (!config.header.authorization) {
userLogin().then(res =>{
if(res){
config.header.authorization = wx.getStorageSync('userInfo').token
resolve(config);
}
})
} else {
resolve(config);
}
});
}
// 響應(yīng)攔截器
function responseInterceptor(response) {
console.log("經(jīng)過響應(yīng)攔截器")
return new Promise((resolve, reject) => {
// 處理響應(yīng)結(jié)果
if (response.data.flag) {
resolve(response);
} else {
if (response.data.code === 40001) {
userLogin().then(res => {
reject(response)
})
} else {
wx.showToast({
title: response.data.message,
icon: "error",
duration: 2000
})
}
}
});
}
/**
* 封裝wx.getUserProfile()方法
*/
function wxGetUserProfile() {
return new Promise((resolve, reject) => {
wx.getUserProfile({
desc: '獲取你的昵稱、頭像、地區(qū)及性別',
success: (res) => {
let userInfo = {
userName: res.userInfo.nickName,
iconUrl: res.userInfo.avatarUrl
}
wx.setStorageSync('userInfo', userInfo)
resolve(userInfo)
},
fail: (res) => {
reject(res)
}
})
})
}
/**
* 封裝wx.login
*/
function wxLogin() {
return new Promise((resolve, reject) => {
wx.login({
success: (res) => {
console.log("wxLogin()獲取驗(yàn)證碼:" + res.code)
resolve(res.code)
},
fail: (res) => {
reject(res)
}
})
})
}
/**
* 封裝后端登陸方法
* @param {驗(yàn)證碼} code
*/
function mpLogin(data) {
return new Promise((resolve, reject) => {
wx.request({
url: serverUrl + '/user/login',
data: data,
method: 'POST',
success: (res => {
resolve(res.data)
}),
fail: (res => {
reject(res)
}),
})
})
}
/**
* 調(diào)用wx.login 和 mplogin 完成用戶后端登陸
*/
async function userLogin() {
let userInfo = wx.getStorageSync('userInfo');
if (!userInfo) {
userInfo = await wxGetUserProfile()
}
if(!userInfo){
return;
}
let code = await wxLogin();
let data = {
code: code,
userName: userInfo.userName,
iconUrl: userInfo.iconUrl
}
return new Promise((resolve, reject) => {
mpLogin(data).then(res => {
if (res.flag) {
console.log("userLogin()登陸成功返回信息:" + res)
wx.setStorageSync('userInfo', res.data)
resolve(true)
} else {
wx.showToast({
title: res.message,
icon: "error",
duration: 2000
})
resolve(false)
}
})
})
}
//post請求,數(shù)據(jù)按照query方式傳給后端
/**
*
* @param {請求地址} url
* @param {請求數(shù)據(jù)} data
* @param {重試次數(shù)} times
*/
function postRequest(url, data = {}, times) {
// 獲取請求頭
let header = CreateHeader(url, 'POST');
return new Promise((resolve, reject) => {
const config = {
url: serverUrl + url,
data: data,
header: header,
method: 'POST',
success: (res => {
// 對響應(yīng)統(tǒng)一處理
responseInterceptor(res)
.then(res => {
resolve(res.data);
}).catch(res => {
// 重
if (times > 0) {
postRequest(url, data, times - 1).then(res => {
resolve(res)
})
} else {
wx.showToast({
title: '請稍后再試',
icon: "loading",
})
}
})
}),
fail: (res => {
reject(res)
}),
}
// 請求攔截器
requestInterceptor(config)
.then(config => {
wx.request(config);
}).catch(error => {
reject(error);
});
})
}
//get 請求
function getRequest(url, data, times) {
let header = CreateHeader(url, 'GET');
return new Promise((resolve, reject) => {
const config = {
url: serverUrl + url,
data: data,
header: header,
method: 'GET',
success: (res => {
responseInterceptor(res)
.then(res => {
resolve(res.data);
}).catch(res => {
// 重
if (times > 0) {
getRequest(url, data, times - 1).then(res => {
resolve(res)
})
} else {
wx.showToast({
title: '請稍后再試',
icon: "loading",
})
}
})
}),
fail: (res => {
reject(res)
})
}
// 請求攔截器
requestInterceptor(config)
.then(config => {
wx.request(config);
}).catch(error => {
reject(error);
});
})
}
//put請求
function putRequest(url, data, times) {
let header = CreateHeader(url, 'PUT');
return new Promise((resolve, reject) => {
const config = {
url: serverUrl + url,
data: data,
header: header,
method: 'PUT',
success: (res => {
responseInterceptor(res)
.then(res => {
resolve(res.data);
}).catch(res => {
// 重
if (times > 0) {
putRequest(url, data, times - 1).then(res =>{
resolve(res)
})
} else {
wx.showToast({
title: '請稍后再試',
icon: "loading",
})
}
})
}),
fail: (res => {
reject(res)
})
}
})
}
//delete請求
function deleteRequest(url, data, times) {
let header = CreateHeader(url, 'DELETE');
return new Promise((resolve, reject) => {
const config = {
url: serverUrl + url,
data: data,
header: header,
method: 'DELETE',
success: (res => {
responseInterceptor(res)
.then(res => {
resolve(res.data);
}).catch(res => {
if (times > 0) {
deleteRequest(url, data, times - 1).then(res =>{
resolve(res)
})
} else {
wx.showToast({
title: '請稍后再試',
icon: "loading",
})
}
})
}),
fail: (res => {
reject(res)
})
}
// 請求攔截器
requestInterceptor(config)
.then(config => {
wx.request(config);
}).catch(error => {
reject(error);
});
})
}
//導(dǎo)入
module.exports = {
getRequest: getRequest,
postRequest: postRequest,
putRequest: putRequest,
deleteRequest: deleteRequest,
userLogin: userLogin,
}
五、使用示范:
const re = require('../../utils/request.js'); // 導(dǎo)入
Page({
btCreateSubject(e){
re.postRequest("/subject/create",{
subjectName:"學(xué)習(xí)強(qiáng)國3"
},2).then(res =>{
console.log("創(chuàng)建科目成功返回?cái)?shù)據(jù):")
console.log(res)
})
},
})
-
在用戶沒有token的情況下:
- 進(jìn)行請求攔截器,調(diào)用了登陸方法:
- 執(zhí)行原來的操作,得到結(jié)果
- 進(jìn)行請求攔截器,調(diào)用了登陸方法:
-
在用戶有token的情況下,但是服務(wù)器已經(jīng)沒有維護(hù)用戶的登陸狀態(tài)了
-
redis當(dāng)中沒有維護(hù)用戶狀態(tài)了
-
原本請求–>登陸請求–>原本請求
文章來源:http://www.zghlxwxcb.cn/news/detail-649509.html
-
后端已經(jīng)維持用戶登陸狀態(tài)
文章來源地址http://www.zghlxwxcb.cn/news/detail-649509.html
-
總結(jié):
- 雖然這樣封裝看起來挺復(fù)雜的,但是對于用戶來說是一種很好的體驗(yàn)。對于普通的網(wǎng)站,如果發(fā)現(xiàn)你你的登陸過期,又得重新輸入密碼注冊。但是這樣我們無全不需要,只要你已經(jīng)是登陸過的用戶,除非你清除了小程序的緩存,否則在你接下來使用過程中都不需要再手機(jī)登陸。
- 其次,對于前端js編寫來說,不需要在每個請求前都去判斷用戶是否本地緩存有token,都在由請求攔截器統(tǒng)一處理。對于請求后的響應(yīng),我們不需要去處理各種情況,只需要處理成功的情況就可以了。
關(guān)于實(shí)現(xiàn)小程序用戶“無感”登陸的方法,我相信這不是最優(yōu)解,但是這是我目前能想到最好的解決辦法了。如果小伙伴有更好的登陸流程,歡迎在評論區(qū)告訴我,一起討論~
到了這里,關(guān)于微信小程序封裝request請求,包含請求攔截器,響應(yīng)攔截器和請求重試功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!