Vue功能篇 - 3.封装axios请求库

每个项目的需求各有偏差,务必根据自己的项目调整相关配置
如大家有什么好的建议,可在评论区回复

Vue封装axios请求库

  • 1.创建 httpload.js 文件
  • 2.创建api文件夹,将以下代码放入index.js
  • 3.vue页面中调用
  • 4.刷新refreshToken 代码 [非必须,根据具体需求使用]

1.创建 httpload.js 文件


import axios from 'axios';
import {
     
    Message,
    Loading
} from 'element-ui';
import router from '../router';
import _ from 'lodash';
import qs from 'qs';

const http = axios.create({
     
    baseURL: process.env.API_HOST, //设置请求的base url
    timeout: 300000, //超时时长5分钟,
    crossDomain: true
});

http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8;multipart/form-data'
//根据具体需求使用该方法 非必须
http.defaults.paramsSerializer = (params) => {
     
    return qs.stringify(params, {
     
        arrayFormat: 'brackets'
    });
}
//loading对象
let loading;

//当前正在请求的数量
let needLoadingRequestCount = 0;

//显示loading
function showLoading(target) {
     
    // 后面这个判断很重要,因为关闭时加了抖动,此时loading对象可能还存在,
    // 但needLoadingRequestCount已经变成0.避免这种情况下会重新创建个loading
    if (needLoadingRequestCount === 0 && !loading) {
     
        loading = Loading.service({
     
            lock: true,
            text: "拼命加载中····",
            background: 'rgba(255, 255, 255, 0.5)',
            target: target || "body"
        });
    }
    needLoadingRequestCount++;
}

//隐藏loading
function hideLoading() {
     
    needLoadingRequestCount--;
    needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); //做个保护
    if (needLoadingRequestCount === 0) {
     
        //关闭loading
        toHideLoading();
    }
}

//防抖:将 300ms 间隔内的关闭 loading 便合并为一次。防止连续请求时, loading闪烁的问题。
var toHideLoading = _.debounce(() => {
     
    if (loading != null) {
     
        loading.close();
    }
    loading = null;
}, 300);

//添加请求拦截器
http.interceptors.request.use(config => {
     
    //判断当前请求是否设置了不显示Loading
    if (config.headers.showLoading !== false) {
     
        showLoading(config.headers.loadingTarget);
    }
    config.url = decodeURI(encodeURI(config.url).replace('%E2%80%8B', "")) //去除url中的空格
    //根据具体需求使用该方法 非必须
    if (config.method === 'post') {
     
        config.data = qs.stringify(config.data);
    }

    const token = sessionStorage.token;
    if (token) {
     
        config.headers.common["Authorization"] = 'Bearer' + token;
    }
    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) {
     
      //refreshTokenFuc(isRefreshToken, config, retryRequests);
     // return Promise.reject(response);
   // }
	return response;
    },
    error => {
     
        //判断当前请求是否设置了不显示Loading(不显示自然无需隐藏)
        // if (error.config.headers.showLoading !== false) {
     
        hideLoading();
        // }
		if(error.response&&error.response.status){
     
			switch (error.response.status) {
     
				//401: 未登录-授权过期
				case 401:
				//授权过期时进行的操作,如返回登录页等
				
				//如有刷新token的需求,可放开以下代码
				//var config=error.config;
				//refreshTokenFuc(isRefreshToken, config, retryRequests);
				break;
			}
			return Promise.reject(error.response);
		}

        // if(error.response && error.response.data && error.response.data.message) {
     
        //   var jsonObj = JSON.parse(error.response.data.message);
        //   Message.error(jsonObj.message);
        // }else{
     
        //   Message.error(error.message);
        // }//     if (error.response.status) {
     
        //       switch (error.response.status) {
     
        //         // 401: 未登录
        //         // 未登录则跳转登录页面,并携带当前页面的路径
        //         // 在登录成功后返回当前页面,这一步需要在登录页操作。
        //         case 401:
        //           router.replace({
     
        //             path: '/login',
        //             query: { redirect: router.currentRoute.fullPath }
        //           })
        //           break
        //         // 403 token过期
        //         // 登录过期对用户进行提示
        //         // 清除本地token和清空vuex中token对象
        //         // 跳转登录页面
        //         case 403:
        //Message.error('登录过期,请重新登录!');
        //           // 清除token
        //           localStorage.removeItem('token')
        //           store.commit('loginSuccess', null)
        //           // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
        //           setTimeout(() => {
     
        //             router.replace({
     
        //               path: '/login',
        //               query: {
     
        //                 redirect: router.currentRoute.fullPath
        //               }
        //             })
        //           }, 1000)
        //           break
        //         // 404请求不存在
        //         case 404:
        //           Message.error('网络请求不存在');
        //           break
        //         // 其他错误,直接抛出错误提示
        //         default:
        //           Message.error(error.response.data.message);
        //       }
        //       return Promise.reject(error.response)
        //     }
        return Promise.reject(error);
    }
);

export default http;


2.创建api文件夹,将以下代码放入index.js

api封装后导出供页面使用

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了! 目前暂无好的解决方法,需要用户点击一下页面上任意的按钮或者刷新页面即可

let isRefreshToken = false;//是否正在刷新token
let retryRequests = []; //用于存储错误请求的数组
// 刷新token方法
function refreshTokenFuc(isRefreshToken, config, retryRequests) {
     
  if (!isRefreshToken) {
     
    isRefreshToken = true;
    var data = {
      refreshtoken: sessionStorage.refreshtoken }
    //TokenApi是自己封装的axios网络请求, 这里替换成你们自己请求后端刷新token的请求即可
    TokenApi.refreshToken(data).then(res => {
     
      sessionStorage.token = res.data.data.token.access_token;
      sessionStorage.refreshtoken = res.data.data.token.refresh_token;
      config.headers["Authorization"] = 'Bearer ' + res.data.data.token.access_token;
      retryRequests.forEach((cb) => cb(res.data.data.token.access_token));
      retryRequests = [];
      return http.request(config);
    }).catch(error => {
     
      message.error("身份验证失败,请重新登录!");
      sessionStorage.clear();
      setTimeout(() => {
     
        router.replace({
     
          path: '/login',
          // query: { redirect: router.currentRoute.fullPath }
        })
      }, 1500)
    }).finally(() => {
     
      isRefreshToken = false;
    })
  } else {
     
   //存储错误的请求,待刷新token完成后,重新发起请求
    return new Promise((resolve) => {
     
      retryRequests.push((token) => {
     
        config.headers["Authorization"] = 'Bearer ' + token;
        resolve(http.request(config))
      })
    })
  }
}

你可能感兴趣的:(vue,vue,http)