api封装记录

请求队列

在开发过程中会遇到一些非必要实时请求,比如埋点。当埋点和主接口同属一个域下时,如果埋点请求数量太多时会影响主接口的请求(同域请求上限)。故而可增加埋点请求队列,一次只能请求一个埋点。

let logQueue = []
let logStatus = 'stop'
export const log = (url, data) => {
    let config = {
        data,
        ...
    }
    logQueue.push(config)

    if(logStatus === 'stop'){
        doLog()
    }
}
const doLog = () => {
    let config = logQueue.pop()
    logStatus = 'pending'
    fetch.ajax(config).finally(() => {
        if(logQueue.length){
            doLog()
        }else{
            logStatus = 'stop'
        }
    })
}

优点:解决了可能存在的请求阻塞问题,用户体验提升
缺点:如果请求队列未请求完成时用户就关闭了页面,可能会导致请求丢失

刷新token机制

在实际开发过程中,我们经常会拿到后端两个token(一个长token,一个短token,长短指时间),短token用于校验用户,长token用于刷新短token。
当请求接口A时,假设短token过期,我们需要用长token来刷新短token,如果刷新成功则不需要用户重新登录,直接再次请求接口A来实现用户无感知token更新以及数据正常回显。

let isRefreshing = false
let requests = []
let request = null
request = (type, url, data = {}, hideToast) => {
    const accessToken = localStorage.getItem("accessToken")
    let config = {
        url,
        data,
        type,
        ...
    }

    let curRequest = null
    if(url === '/api/refresh'){
        // 刷新接口单独定义处理逻辑
        curRequest = fetch
        .ajax(config)
        .then(xhr => {
            const { resp } = xhr
            if (resp?.code === 200) {
                const accessToken = resp?.data?.accessToken
                const refreshToken = resp?.data?.refreshToken
                localStorage.setItem("accessToken", accessToken)
                localStorage.setItem("refreshToken", refreshToken)

                config.headers.Authorization = accessToken
                // 重新执行刷新token期间待执行接口
                requests.forEach(cb => cb(accessToken))
            } else {
                !hideToast && toastContent("Login information expired.", 'error')
                // 重新执行刷新token期间待执行接口
                requests.forEach(cb => cb())
                toLogin()
            }

            return xhr
        })
        .catch(() => {
            !hideToast && toastContent("Login information expired.", 'error')
            // 重新执行刷新token期间待执行接口
            requests.forEach(cb => cb())
            toLogin()
        })
        .finally(() => {
            requests = []
            isRefreshing = false
        })
    }else if(isRefreshing){
        // token刷新期间,返回promise,并将该次请求存储在requests数组内
        return new Promise(resolve => {
            requests.push(token => {
            	// token刷新接口调用后,如果token有值则重新调用接口,否则抛出异常
                if(token){
                    config.headers.Authorization = token
                    resolve(fetch.ajax(config).then(xhr => xhr?.resp))
                }else{
                    resolve({code: -1001, loginError: true})
                }
            })
        })
    }else{
        curRequest = fetch
        .ajax(config)
        .then(xhr => {
            const { resp } = xhr
            if(resp?.code === xxx){
                requests = []
                !hideToast && toastContent("Login failed.", 'error')
                toLogin()
                return {code: -1001, loginError: true}
            }else if (resp?.code === 411) {
            	// token过期
                const refreshToken = localStorage.getItem("refreshToken")
            	// 如果token不在刷新期间则调用刷新
                if (!isRefreshing) {
                    isRefreshing = true
                    userService.tokenRefresh({ refreshToken, hideToast })
                }
                // 返回promise,并将该次请求存储在requests数组内
                return new Promise(resolve => {
                    requests.push(token => {
            			// token刷新接口调用后,如果token有值则重新调用接口,否则抛出异常
                        if(token){
                            config.headers.Authorization = token
                            resolve(fetch.ajax(config).then(xhr => xhr?.resp))
                        }else{
                            resolve({code: -1001, loginError: true})
                        }
                    })
                })
            }
            return resp
        })
        .catch(error => {
            toastContent("Server Error!", 'error')
            return {code: -1002, serverError: true}
        })
    }
    
    curRequest.xhr = fetch.currentXHR
    return curRequest
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风舞红枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值