每个项目的需求各有偏差,务必根据自己的项目调整相关配置
如大家有什么好的建议,可在评论区回复!
- 动态地址(需注释baseUrl)
- 在public创建config.js,里面为api地址
- 各个api文件夹中引入即可,然后拼接到api上 - 静态地址
配置baseUrl即可
Vue封装axios请求库
1.创建 httpload.js 文件
import qs from 'qs';
import axios from 'axios';
import { message } from 'element-plus';
import router from '../router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
message.config({
duration: 2,
maxCount: 3
});
NProgress.configure({ showSpinner: false });
const http = axios.create({
baseURL: process.env.API_HOST, //设置请求的base url,也可不设置这里,在api文件里直接拼接api
timeout: 300000, //超时时长5分钟,
crossDomain: true
});
http.defaults.headers.post['Content-Type'] ='multipart/form-data;application/json;charset=UTF-8;';
//当前正在请求的数量
let needLoadingRequestCount = 0;
// 显示loading
function showLoading() {
// 后面这个判断很重要,因为关闭时加了抖动,此时loading对象可能还存在,
// 但needLoadingRequestCount已经变成0.避免这种情况下会重新创建个loading
if (needLoadingRequestCount === 0) {
NProgress.start();
}
needLoadingRequestCount++;
}
// 隐藏loading
function hideLoading() {
needLoadingRequestCount--;
needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); // 做个保护
if (needLoadingRequestCount === 0) {
NProgress.done();
}
}
//添加请求拦截器
let tempConfig = '';
http.interceptors.request.use(config => {
//判断当前请求是否设置了不显示Loading
if (config.headers.showLoading !== false) {
showLoading();
}
config.url = decodeURI(encodeURI(config.url).replace('%E2%80%8B', "")) //去除url中的空格
const token = sessionStorage.token;
if (token) {
config.headers.common["Authorization"] = 'Bearer' + token;
}
tempConfig = config;
return config;
}, err => {
//判断当前请求是否设置了不显示Loading
if (config.headers.showLoading !== false) {
hideLoading();
}
message.error('请求超时!');
return Promise.resolve(err);
});
//响应拦截器
http.interceptors.response.use(
response => {
//判断当前请求是否设置了不显示Loading(不显示自然无需隐藏)
if (response.config.headers.showLoading !== false) {
hideLoading();
}
//如有刷新token的需求,可放开以下代码
//if (response.status === 401) {
//return refreshTokenFuc(tempConfig);
// }
return response;
},
error => {
hideLoading();
if(error.response&&error.response.status){
switch (error.response.status) {
//401: 未登录-授权过期
case 401:
//如有刷新token的需求,可放开以下代码
//return refreshTokenFuc(error.config);
break;
case 500:
message.error(error.response.data.message);
break;
case 503:
message.error('温馨提示:服务不可用,状态码:503');
break;
}
return Promise.reject(error.response);
}
if (axios.isCancel(error)) {
//取消请求
} else {
message.error('服务器打瞌睡了');
}
return Promise.reject(error.response);
}
);
export default http;
2.创建api文件夹,将以下代码放入index.js
- api封装后导出供页面使用
- 可以直接拼接url,此时可不配置httpload里的baseurl
import request from "@/http/httpload.js"
export default{
getData(data){
return request({
url:"/api/xxx",
method:"post",
data:data
})
},
getManyData(data){
return request({
url:"/api/xxx",
method:"get",
parmas:data
})
}
}
3.vue页面中调用
<template>
<div>
<el-button class="el-icon-user" @click="getData">获取数据</el-button>
</div>
</template>
<script>
import Task from "@/api/index.js";
export default {
name: "testDemo",
methods: {
getData() {
var data={id:'xxxxxxx'}
Task.getData(data).then(res => {
console.log(res);
}).catch(error=>{
console.log(error);
});
}
}
};
</script>
4.刷新refreshToken 代码 [非必须,根据具体需求使用]
如有刷新token的需求,将以下代码放入httpload.js文件中即可,
注:以下代码必须放到 响应拦截请求前
待解决问题:刷新refreshToken后,新Token获取正常,并重新自动请求了之前错误的请求,数据返回是正常的,但页面并不会重新渲染,因为数据请求时已经catch了! 目前暂无好的解决方法,需要用户点击一下页面上任意的按钮或者刷新页面即可
//页面重定向
function pageRedirect() {
message.error('登录信息已过期,请重新登录!');
setTimeout(() => {
//routeRedirect(); 跳转页面
}, 1500);
}
//检测值是否存在
function checkRefreshIsExit(token) {
if (!token || token === null || token === 'undefined') {
return false;
}
return true;
}
let isRefreshToken = false; // 正在刷新token
let refreshCount = 0;
// 刷新token方法
async function refreshTokenFuc(config) {
refreshCount++;
if (!isRefreshToken) {
const temp = {
client_id: 'login',
client_secret: '123456',
grant_type: 'refresh_token',
refresh_token: isUseBaseToken ? sessionStorage.refreshBaseToken : sessionStorage.refreshToken,
};
const isExitToken = await checkRefreshIsExit(temp.refresh_token);
if (!isExitToken) {
pageRedirect();
return;
}
return TokenApi.userToken(temp).then((res) => {
isRefreshToken = true;
const { data } = res;
if (data.code > -1) {
let tempToken = data.access_token;
sessionStorage.baseToken = data.access_token;
sessionStorage.refreshBaseToken = data.refresh_token;
config.headers.Authorization = `Bearer ${tempToken}`;
return http(config);
} else {
pageRedirect();
}
}).catch((error) => {
if (refreshCount === 3 || error.status === 400 || !sessionStorage.baseToken) {
pageRedirect();
} else {
refreshTokenFuc(config);
}
}).finally(() => {
refreshCount = 0;
isRefreshToken = false;
})
}
}
5.取消请求及阻止重复请求 [非必须,根据具体需求使用]
通过AbortController将多次访问的api取消
let httpList = [];
const removeHttp = config => {
const { method, url, params, data } = config;
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&');
let index = httpList.findIndex(v => {
const tempRequestKey = [v.method, v.url, qs.stringify(v.params), qs.stringify(v.data)].join('&');
if (requestKey === tempRequestKey) {
return true;
}
});
if (index >= 0) {
httpList[index].controller.abort();
httpList.splice(index, 1);
}
}
http.interceptors.request.use(
(config) => {
removeHttp(config);
//....其它省略
//增加自动取消重复请求功能
const controller = new AbortController();
config.signal = controller.signal;
config.controller = controller;
httpList.push({ ...config });
}
// 响应拦截器
http.interceptors.response.use(
(response) => {
//.....其它省略
},
(error) => {
//.....其它省略
if (axios.isCancel(error)) {
//取消请求
} else {
message.error('温馨提示:数据获取失败');
}
//.....其它省略
},