vue3 axios请求与响应拦截-封装axios、附加token以及错误全局处理

本内容会随着我的系统的编写,不断改进。也欢迎大家有任何问题或改进随时评论。谢谢

解决问题

  1. 发出请求时自动在请求头中添加token;
  2. 对服务器响应进行全局性错误处理;
  3. 对axios请求进行统一封装

标准http响应数据结构(部分)

{
	status:200,
	 message:'信息',
	 data:Object
}

本例中http标准响应数据结构中data的结构为:

{ 
 	code:200,
   	success:true, 
    msg:'信息’, 
     data:Object 
}

示例

/**
*
*@author MuYi
*@date 2022/4/3 21:52
*@version 1.0
*/

import request from "@/utils/request";
import store from "@/store";

/**
* 获取app软件信息
* @param username
* @return {Promise<void>}
*/
const getAppInfo = async (username) => {
 try {
   let url = "/system/getAppInfo"
   let result = await request.post(url)
   if (result.data.data && result.data.success)
     store.commit("saveAppInfo", result.data.data)
 } catch (e) {
   store.commit('resetTheme')
 }
}
export {getAppInfo}

axios配置及工具

axios工具

/**
 * 封装axios 请求方法
 *@author MuYi
 *@date 2022/3/28 17:03
 *@version 1.0
 */
import instance from "@/utils/axiosInstance";

/**
 * axios的get、post、put、patch、delete请求
 */
class Request {


  /**
   * axios的get请求。用于获取数据。
   * @param url 地址
   * @param args 任意个可变参数。可不输入,直接写在url中
   */
  get(url) {
    if (arguments.length > 0) {
      if (url.endsWith("/")) url = url.substring(0, url.length - 1);
      let result = "";
      for (let i = 0; i < arguments.length; i++) {
        result += "/" + arguments[i];
      }
      url = url + result;
    }
    return instance({
      method: 'GET',
      url: url,
    })
  }


  /**
   * axios的post请求。用于提交数据(新建)、包括表单提交及文件上传。
   * @param url 地址
   * @param data 参数
   */
  post(url, data) {
    return instance({
      method: 'POST',
      url: url,
      data: data
    })
  }

  /**
   * axios的put请求。用于更新数据(修改),将所有数据都推送到后端。

   * @param url 地址
   * @param data 参数
   */
  put(url, data) {
    return instance({
      method: 'PUT',
      url: url,
      data: data
    })
  }

  /**
   * axios的patch请求。用于更新数据(修改),只将修改的数据推送到后端。
   * @param url 地址
   * @param data 参数
   */
  patch(url, data) {
    return instance({
      method: 'PATCH',
      url: url,
      data: data
    })
  }

  /**
   * axios的delete请求。用于删除数据。
   * @param url 地址
   * @param data 参数
   */
  delete(url, data) {
    return instance({
      method: 'DELETE',
      url: url,
      data: data
    })
  } 
} 

export default new Request() 

axios配置方法:

/**
 * request拦截器
 *@author MuYi
 *@date 2022/3/29 10:16
 *@version 1.0
 */
import {getToken} from "./authority"
import axios from 'axios';
import {ElMessageBox, ElMessage, Loading} from 'element-plus';
import {logout} from "@/api/login"
import {tansParams,blobValidate} from "@/utils/tools/muyi-tools";
import router from "@/router";

// axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
let axiosInstance = axios.create({
    baseURL: '/api',//axiosConfig.axios.baseUrl.value,
    timeout: 100000,//axiosConfig.axios.timeout.value,
    responseType: "json",
    responseEncoding: 'utf8',
})


/**
 * 请求拦截
 * <pre>
 * 写入token
 * </pre>
 */
axiosInstance.interceptors.request.use(
    config => {
        let token = getToken()
        if (token!==null && token !=='') config.headers['Authorization'] = token;
        return config;
    },
    error => {
        console.log("请求出错,错误信息如下:");
        console.log(error);
        Promise.reject(error);
    });

/**
 * 响应拦截
 * <pre>
 *   错误代码一般有两个:response.status(标准)、response.data.code(非标准,code为自定义命名)
 *   两者可能不一致
 *   response=>拦截response.status为100-399类
 *   error=>拦截response.status为非100-399类
 * </pre>
 */
axiosInstance.interceptors.response.use(
    //后台返回response.status虽为成功
    response => {
        if (response.data!=null) {
            const res = response.data
            if (res.code!==undefined && res.msg!==undefined) {
                //response.data.code为错误代码
                if (response.status !== 200 || res.code !== 200 || !res.success) {
                    const code = res.code;
                    const msg = res.msg || "请联系管理员解决";
                    showCodeMsg(code, msg);
                    // return Promise.reject( msg)
                }
                return response.data
            }
        }
        return getErrResultData(response.status, "非系统服务器返回数据格式");
    },
    //response.status为错误类的处理
    error => {
        let msg;
        let status=error.response.status;
        if (error.response.data.code === undefined) console.log('response err:\n' + JSON.stringify(error.response));
        if (error.response) {
            const res = error.response.data
            if (res.code!==undefined && res.msg!==undefined) {
                msg = res.msg || "请联系管理员解决";
                showCodeMsg(status, msg);
            }else{
                if( status=='404') {
                    showCodeMsg(404, "请求不存在<br/>"+error.response.config.url);
                }
                else if(String(error.response.data).includes('ECONNREFUSED'))
                    showMsg('数据服务器离线,请联系管理员');
                else showMsg('未知异常,请联系管理员');
            }
        } else if (error.message.includes('timeout')) {
            showMsg('请求超时,请检查网络连接!');
        } else {
            showMsg(error.message, 30, '未知异常');
        }
        // 下面会在控制台显示“Uncaught (in promise) Error: Request failed with status code XXX"
        // 错误信息以显示,再抛出异常无意义
        // return Promise.reject(error.response.data)
        return getErrResultData(status, "非系统服务器返回数据格式");
    }
);

function showCodeMsg(code, msg) {
    if (code === 401) {
        process401();
        return Promise.reject('无效/过期的会话,请重新登录。')
    } else if (code === 400) {
        showMsg(msg, 30, '客户端错误');
    } else if (code === 403) {
        showMsg(msg || '权限不足');
    } else if (code === 404) {
        showMsg(msg || '请求不存在');
    } else if (code === 500) {
        showMsg(msg, 30, '服务器异常');
    } else if (code === 501) {
        showMsg(msg || '您的操作被取消或不允许提交');
    } else {
        showMsg(msg, 30, '其他异常');
    }
}

/**
 * 显示信息
 * @param msg 主信息
 * @param duration 停留时间,秒。不输入或null默认30
 * @param auxMsg 小字号显示的附加信息
 * @param data 携带数据
 */
function showMsg(msg, duration, auxMsg, data) {
    const hasData = data != null && data !== '';
    const hasAuxMsg = auxMsg != null && auxMsg !== "";
    let message = "<p><strong>" + msg + "</strong></p>";
    if (hasData) message += "<br/><p><small>返回数据:" + JSON.stringify(data) + "</small></p>";
    if (hasAuxMsg) message += "<br/><small><i>" + auxMsg + "</i></small>";
    if (duration == null) duration = 30000;
    else duration = duration * 1000;
    ElMessage({
        duration: duration,
        showClose: true,
        message: message,
        grouping: true,
        type: 'error',
        dangerouslyUseHTMLString: true,
    })
}

function process401() {
    ElMessageBox.confirm('无效/过期的服务器访问,请重新登录。', '确定登出', {
        confirmButtonText: '重新登录',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        logout().then(() => {
            location.reload()// 重实例化router
        })
    })
}

function getErrResultData(code, msg) {
    return {
        code: code, msg: msg, success: false, data: null
    };
}
// let downloadLoadingInstance;
// export function download(url, params, filename) {
//     downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
//     return axiosInstance.post(url, params, {
//         transformRequest: [(params) => { return tansParams(params) }],
//         headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
//         responseType: 'blob'
//     }).then(async (data) => {
//         const isLogin = await blobValidate(data);
//         if (isLogin) {
//             const blob = new Blob([data])
//             saveAs(blob, filename)
//         } else {
//             const resText = await data.text();
//             const rspObj = JSON.parse(resText);
//             const errMsg = rspObj.msg
//             showMsg(errMsg);
//         }
//         downloadLoadingInstance.close();
//     }).catch((r) => {
//         console.error(r)
//         showMsg('下载文件出现错误,请联系管理员!')
//         downloadLoadingInstance.close();
//     })
// }
export default axiosInstance;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

muyi517

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

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

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

打赏作者

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

抵扣说明:

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

余额充值