简介:

在微信小程序开发过程中,网络请求是开发中最基础也是最核心的需求,封装一个稳定且可用性高的请求也显得尤为重要。通常封装的内容除了入参之外,更多的是请求中的异常处理。在处理 token 异常方面的做法,通过维护请求队列,实现重发请求,减少 token 重复请求。

步骤:

  1. 正常业务请求
  2. 检查该请求地址是否需要登录后访问,如果不需要,则直接访问,该请求结束
  3. 如果需要,则判断缓存Token是否存在,如果不存在,则直接跳转登录,如果存在,进入步骤4
  4. 请求后端接口,请求token未过期,则正常返回业务数据,如果请求token过期,则进入步骤5
  5. 调用Token刷新接口,刷新token过期,则直接跳转登录
  6. 刷新token没有过期,则获取token,并存入缓存 进入步骤7
  7. 在客户无感知(无痛)情况下继续请求最初的业务请求,将结果返回

需要注意:请求如果没有限制处理,有多个请求同时到达,就会发起多个 updateToken 请求,其实我们并不想这样,只需要请求一个updateToken即可,其他则直接排队,等待第一个拿到后,直接使用

request1.js代码

let isRefreshing = true; // 请求锁
let pendings = []; // 请求列表
const pathArr = ['pages/buy-goods/index']; // 不需要登录的路径
const baseUrl = "http://192.168.0.112:9999";// 基础路径

function request({method, url, data, options = {
    needLogin: true
}}) {
    const token = wx.getStorageSync('tokenInfo')
    const pages = getCurrentPages();
    const router = pages[pages.length - 1]['route']; // 当前路由
    if (pathArr.includes(router)) options.needLogin = false; // 当前路径是否需要登录
    return new Promise((resolve, reject) => {
        // 需要登录 但是 token不存在 跳转登录
        if (!token && options.needLogin) {
            wx.redirectTo({
                url: '/pages/login/login',
            })
            return
        }
        wx.showNavigationBarLoading();
        wx.showLoading({
            title: '数据加载中...',
            mask: true
        })
        // 请求主体
        wx.request({
            url: baseUrl + url,
            header:{
                Authorization:token.access_token
            },
            method,
            data,
            success(res) {
                let code = res.data.code
                if (code == '9898') {
                    resolve(res.data)
                } else if (code == '200') {
                    if (isRefreshing) {
                        updateToken();
                        isRefreshing = false;
                        pendings.push(() => {
                            resolve(request({method, url, data, options}))
                        })
                    }
                } else {
                    resolve(res.data);
                }
            },
            fail(err) {
                reject(err);
            },
            complete() {
                wx.hideNavigationBarLoading();
                wx.hideLoading();
            }
        })
    })
}
// 刷新token
function updateToken() {
    const token = wx.getStorageSync('tokenInfo');
    const userId = token.user_id;
    const refreshToken = token.refresh_token;
    wx.request({
        url: baseUrl + '/user/refreshToken',
        method: 'POST',
        data: {
            userId: userId,
            refreshToken: refreshToken
        },
        success(res) {
            let code = res.data.code
            if (code == '200') {
                wx.setStorageSync('tokenInfo', {
                    access_token: res.data.data.accessToken,
                    refresh_token: res.data.data.refreshToken,
                    user_id: res.data.data.userId,
                });
                pendings.map((callback) => {
                    callback();
                })
                isRefreshing = true;
            } else {
                toLogin();
            }
        }
    })
}
// 前往登录页面 清空状态
function toLogin() {
    wx.showToast({
        title: '登录失效,请重新登录',
        icon: "none",
        success: () => {
            setTimeout(() => {
                wx.redirectTo({
                    url: '/pages/login/login',
                })
                pendings = [];
                isRefreshing = true;
            }, 1200);
        }
    })
}
module.exports = {
    request
};

业务js

import {
    request
} from '../../request/request1.js';
Page({

    /**
     * 页面的初始数据
     */
    data: {

    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        const orderId = options.orderId;
        this.queryOrderQuoteList(orderId);
    },

    async queryOrderQuoteList(orderId){
        const res = await request({
            method:"POST",
            url:"/order-quote/queryOrderQuoteList",
            data:{
            orderId: orderId,
            pageNum: 1,
            pageSize: 10
            }
        });
        console.log(res);
    }
})