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

文章目录

  • 解决问题
  • 示例
  • axios配置及工具
    • axios工具
    • axios配置方法:

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

解决问题

  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}
*/
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',
})


/**
 * 请求拦截
 * 
 * 写入token
 * 
*/ 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); }); /** * 响应拦截 *
 *   错误代码一般有两个:response.status(标准)、response.data.code(非标准,code为自定义命名)
 *   两者可能不一致
 *   response=>拦截response.status为100-399类
 *   error=>拦截response.status为非100-399类
 * 
*/ 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, "请求不存在
"+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 = "

" + msg + "

"; if (hasData) message += "

返回数据:" + JSON.stringify(data) + "

"; if (hasAuxMsg) message += "
" + auxMsg + ""; 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;

你可能感兴趣的:(#,vue3项目实例,Vue3,vue,前端)