第一步安装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},否则自定义的头部信息会无效.