uniapp 二次封装axios 无感刷新token

第一步安装axios

npm install axios@1.6.8

第二步配置axios请求拦截器类request.js

import axios from "axios"
import config from "../config/cogfig.js"
import qs from 'qs'
import store from "../store/index.js"
import router from 'uniapp-router'
import settle from 'axios/lib/core/settle'
import buildURL from 'axios/lib/helpers/buildURL'
//import mpAdapter from "axios-miniprogram-adapter";
import {
    getToken
} from "../util/auth.js"

// 是否正在刷新的标记 -- 防止重复发出刷新token接口--节流阀
let isRefreshing = false
// 失效后同时发送请求的容器 -- 缓存接口
let subscribers = []

let tryCount = 0;

const isTokenExpired = () => { // 验证当前token是否过期
    let expireTime = store.state.expires_time
    if (expireTime) {
        let nowTime = parseInt(new Date().getTime() / 1000)
        let willExpired = (expireTime - nowTime) < 60 // 如果超过60秒重新获取token
        return willExpired
    }
    return false
}


// 刷新 token 后, 将缓存的接口重新请求一次
function onAccessTokenFetched(newToken) {

    subscribers.forEach((callback) => {
        callback(newToken)
    })
    // 清空缓存接口
    subscribers = []

}
// 添加缓存接口
function addSubscriber(callback) {
    subscribers.push(callback)
}

const service = axios.create({
    timeout: 8000
})

// 请求拦截
service.interceptors.request.use(function(config) {

let token = store.getters.token;
     config.headers['Content-Type'] =`application/x-www-form-urlencoded; charset=UTF-8`;
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    config.headers ={...config.headers,};

    return config
}, function(error) {
    return Promise.reject(error)
})

// 响应拦截
service.interceptors.response.use(function(response) {
        console.log("结果", response)

        /* if (( isTokenExpired()||response.status === 401) && !response.config.url.includes(
                '/oauth/token')) { // 如果token快过期了
                
                
                console.log("如果token快过期了")
            if (!isRefreshing) { // 控制重复获取token
                isRefreshing = true
                var refresh_token = store.state.refresh_token;
                post("/oauth/token", qs.stringify({
                    refresh_token: refresh_token,
                    grant_type: "refresh_token"
                })).then(res => {
                    isRefreshing = false
                     //if (res.status === 200) {
                    if (res.access_token) {
                        store.dispatch('loginIn', res)
                        onAccessTokenFetched(res.access_token)
                    }else{
                        
                    }
                }).catch(() => {
              
                    router.push({
                        path: '/login'
                    }) // 失败就跳转登陆
                    isRefreshing = false
                })

                // 将其他接口缓存起来 
                const retryRequest = new Promise((resolve) => {
                    // 返回Promise并且让其状态一直为等待状态,
                    // 只有当token刷新成功后, 就会调用通过addSubscriber函数添加的缓存接口,
                    // 此时, Promise的状态就会变成resolve
                    addSubscriber((newToken) => {
                        // 表示用新的token去替换掉原来的token
                        response.config.headers.Authorization = 'Bearer ' + newToken
                        // 替换掉url -- 因为baseURL会扩展请求url
                        response.config.url = response.config.url.replace(response.config
                            .baseURL, '')
                        // 用重新封装的config去请求, 就会将重新请求后的返回
                        resolve(service(response.config))
                    })
                })
                return retryRequest.data

            }
            
            console.log("token快过期了")
        } */
        return response.data
    },
    function(error) {
        console.log("网络连接失败", error)
        let response = error.response;

        if (response.status === 401 && !response.config.url.includes('/login')) { // 如果token快过期了
            const {config} = error
            if (!isRefreshing) { // 控制重复获取token
                isRefreshing = true
                var refresh_token = store.state.refresh_token;
                post("/login", qs.stringify({
                    refresh_token: refresh_token,
                    grant_type: "refresh_token"
                })).then(res => {
                    isRefreshing = false
                    if (res.access_token) {
                        var access_token =res.access_token
                        config.headers.Authorization = `Bearer ${access_token}`
                        store.dispatch('loginIn', res)
                        onAccessTokenFetched(access_token)
                    } else {
                        console.log("刷新Token失败");
                    }
                }).catch(() => {
                    console.log("失败跳转登陆");
                    uni.showToast({
                        title: "无法获取个人信息",
                        icon: 'none',
                        duration: 2000
                    })
                    setTimeout(function() {    
                        var url = "/pages/login/login";
                        uni.reLaunch({
                            url
                        });
                        //uni.$emit('wxlogin',{msg:'微信登录'})        
                    }, 3000)
                    isRefreshing = false
                })
            }
            // 将其他接口缓存起来 
            const retryRequest = new Promise((resolve) => {
                // 返回Promise并且让其状态一直为等待状态,
                // 只有当token刷新成功后, 就会调用通过addSubscriber函数添加的缓存接口,
                // 此时, Promise的状态就会变成resolve
                addSubscriber((newToken) => {
                    // 表示用新的token去替换掉原来的token
                    response.config.headers.Authorization = 'Bearer ' + newToken
                    // 替换掉url -- 因为baseURL会扩展请求url
                    response.config.url = response.config.url.replace(response.config.baseURL, '')
                    // 用重新封装的config去请求, 就会将重新请求后的返回
                    resolve(service(response.config))
                })
            })
            return retryRequest
        }
        return Promise.reject(error)
    })

service.defaults.adapter = function(config) {
    return new Promise((resolve, reject) => {
    
        console.log("config:",config.headers);
        uni.request({
            method: config.method.toUpperCase(),
            url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
            header: {...config.headers},
            data: config.data,
            dataType: config.dataType,
            responseType: config.responseType,
            sslVerify: config.sslVerify,
            complete: function complete(response) {
                response = {
                    data: response.data,
                    status: response.statusCode,
                    errMsg: response.errMsg,
                    header: response.header,
                    config: config
                };
                
                settle(resolve, reject, response);
            }
        })
    })
}

function request(options) {
    options.method = options.method ? options.method : 'get'
    if (options.method.toLowerCase() == 'get') {
        options.params = options.data
    }
    if (config.env == 'production') {
        service.defaults.baseURL = config.baseApi

    } else {
        service.defaults.baseURL = config.baseApi
    }
    
    return service(options)
}

function post(url, params) {
    return new Promise((resolve, reject) => {
        request({
                url: url,
                method: 'post',
                data: params
            
            })
            .then(response => {
                resolve(response);
            }, err => {
                reject(err);
            }).catch(
                (error => {
                    reject(error)
                }))
    })
}

function get(url, params) {
    return new Promise((resolve, reject) => {
        request({
                url: url,
                method: 'get',
                data: params
            })
            .then(response => {
                
                resolve(response);
            }, err => {
                reject(err);
            }).catch(
                (error => {
                    reject(error)
                }))
    })
}

export default {
    post,
    get
}

注:适配器设置头部信息应写出header: {...config.headers},否则自定义的头部信息会无效.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值