美文网首页
axios 封装

axios 封装

作者: Cherry丶小丸子 | 来源:发表于2021-04-25 00:00 被阅读0次

首先看一下我的 项目 目录 结构

项目目录结构.png
1)创建axios目录,依次创建axios.js、base.js、index.js
axios.js
/**
 * axios封装
 * 请求拦截、响应拦截、错误统一处理
 */
import axios from 'axios';
import router from '@/router/index.js';
// import store from '../store/index'; // vuex

// element-ui的MessageBox, Message的消息提示组件,可根据自己的ui组件更改。
import { Message, MessageBox } from 'element-ui';

// 创建axios实例
let instance = axios.create();
console.log('axios实例默认:', instance.defaults);
// 设置请求超时
instance.defaults.timeout = 10000;
// 表示跨域请求时是否需要使用凭证
instance.defaults.withCredentials = true;
// 环境的切换
// `baseURL` 将自动加在 `url` 前面
/* if (process.env.NODE_ENV == 'development') {
    instance.defaults.baseURL = 'https://www.baidu.com';
}else if (process.env.NODE_ENV == 'test') {
    instance.defaults.baseURL = 'https://www.tencent.com';
}else if (process.env.NODE_ENV == 'production') {
    instance.defaults.baseURL = 'https://www.alibaba.com';
} */

// 设置post请求头    application/x-www-form-urlencoded;application/json;
instance.defaults.headers.common['Authorization'] = 'AUTH_TOKEN';
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8;';

instance.all = axios.all; // 设置axios并发请求

// 添加请求拦截器
instance.interceptors.request.use(config => {
    console.log('请求拦截器:', config);
    // 在发送请求之前做些什么
    
    /* 登录流程控制中,根据本地是否存在token判断用户的登录情况
    但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
    后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
    而后我们可以在响应拦截器中,根据状态码进行一些统一的操作 */
    if(window.localStorage.zsyftxglptMh != 'undefined' && window.localStorage.zsyftxglptMh != null){
        const token = JSON.parse(window.localStorage.zsyftxglptMh).token;
        token && (config.headers.Authorization = 'Bearer ' + token);
    }
    return config;
}, error => {
    // 对请求错误做些什么
    console.log(error)
    return Promise.reject(error);
});

// 添加响应拦截器  
instance.interceptors.response.use(response => {
    console.log('响应拦截器:', response);
    // 对响应数据做点什么
    
    // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据,否则的话抛出错误
    if (response.status === 200) {
        return Promise.resolve(response);
    } else {
        return Promise.reject(response);
    }
    // return response;
}, error => { // 服务器状态码不是200的情况
    // 对响应错误做点什么
    
    console.log(Object.entries(error));
    const { config, code, request, response, isAxiosError, toJSON } = error;
    if (response) {
        // 请求已发出,但是不在2xx的范围 
        errorHandle(response.status, response.data.message);
        return Promise.reject(response);
    }else {
        // 超时提示
        if(error.message.includes('timeout')){
            MessageBox.alert('请求超时,请稍后重试', '提示', {
                lockScroll: true,
                confirmButtonText: '确定',
                closeOnClickModal: false,
                closeOnPressEscape: false,
            });
            return Promise.reject(error);
        }

        /* 处理断网的情况
        eg:请求超时或断网时,更新state的network状态
        network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
        关于断网组件中的刷新重新获取数据,会在断网组件中说明 */
        if (!window.navigator.onLine) {
            // 如果断网....
            // store.commit('changeNetwork', false);
        } else {
            return Promise.reject(error);
        }
    }
});

/** 
 * 请求失败后的错误统一处理 
 * @param {Number} status 请求失败的状态码
 * 1**  信息,服务器收到请求,需要请求者继续执行操作
 * 2**  成功,操作被成功接收并处理
 * 3**  重定向,需要进一步的操作以完成请求
 * 4**  客户端错误,请求包含语法错误或无法完成请求
 * 5**  服务器错误,服务器在处理请求的过程中发生了错误
 */

/**
 * 100  继续。客户端应继续其请求
 * 101  切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
 * 
 * 200  请求成功。一般用于GET与POST请求
 * 201  已创建。成功请求并创建了新的资源
 * 202  已接受。已经接受请求,但未处理完成
 * 203  非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
 * 204  无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
 * 205  重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
 * 206  部分内容。服务器成功处理了部分GET请求
 * 
 * 300  多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
 * 301  永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
 * 302  临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
 * 303  查看其它地址。与301类似。使用GET和POST请求查看
 * 304  未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
 * 305  使用代理。所请求的资源必须通过代理访问
 * 306  已经被废弃的HTTP状态码
 * 307  临时重定向。与302类似。使用GET请求重定向
 * 
 * 400  客户端请求的语法错误,服务器无法理解
 * 401  请求要求用户的身份认证
 * 402  保留,将来使用
 * 403  服务器理解请求客户端的请求,但是拒绝执行此请求
 * 404  服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
 * 405  客户端请求中的方法被禁止
 * 406  服务器无法根据客户端请求的内容特性完成请求
 * 407  请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
 * 408  服务器等待客户端发送的请求时间过长,超时
 * 409  服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
 * 410  客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
 * 411  服务器无法处理客户端发送的不带Content-Length的请求信息
 * 412  客户端请求信息的先决条件错误
 * 413  由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
 * 414  请求的URI过长(URI通常为网址),服务器无法处理
 * 415  服务器无法处理请求附带的媒体格式
 * 416  客户端请求的范围无效
 * 417  服务器无法满足Expect的请求头信息
 * 
 * 500  服务器内部错误,无法完成请求
 * 501  服务器不支持请求的功能,无法完成请求
 * 502  作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
 * 503  由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
 * 504  充当网关或代理的服务器,未及时从远端服务器获取请求
 * 505  服务器不支持请求的HTTP协议的版本,无法完成处理
 */
const errorHandle = (status, other) => {
    // 状态码判断
    switch (status) {
        // 400: 请求错误
        case 400:
            MessageBox.alert('请求错误', '提示');
            break;
        // 401: 未登录状态,跳转登录页
        case 401:
            loginOut();
            break;
        // 403 权限不足,拒绝访问
        case 403:
            MessageBox.alert('权限不足,拒绝访问', '提示');
            break;
        // 404请求不存在
        case 404:
            MessageBox.alert('请求的资源不存在或请求地址出错', '提示');
            break;
        // 服务器错误
        case 500:
            MessageBox.alert('服务器错误', '提示');
            break;
        // token异常
        case 1000001:
            MessageBox.alert("token异常,请联系管理员", '提示');
            break;
        default:
            console.log(other);
    }
}

/** 
 * 跳转登录页
 * 携带当前页面路由,在登录页面完成登录后返回当前页面
 */
const loginOut = () => {
    if(window.localStorage.loginOut == 'false'){ // 解决:token验证过期,发送多次请求,导致消息多次提示
        window.localStorage.loginOut = 'true'; // 更改状态,防止发送多次请求,导致消息多次提示
        MessageBox.alert('登陆状态已过期,请重新登录', '提示', {
            lockScroll: true,
            confirmButtonText: '确定',
            closeOnClickModal: false,
            closeOnPressEscape: false,
            callback:() => {
                router.replace({
                    path: '/',
                    query: {
                        redirect: router.currentRoute.fullPath
                    }
                });
                window.localStorage.removeItem('zsyftxglptMh');
            }
        });
    }
}

export default instance;
base.js
/**
 * 接口域名的管理
 */
const baseUrl = {
    ddns: 'http://192.168.20.133:8090',
    ddns1: process.env.VUE_APP_URL
}
export default baseUrl;
index.js
/** 
 * api接口统一出口管理
 */
import login from '@/axios/login/login.api.js'; // 登录
import home from '@/axios/home/home.api.js'; // 主页

export default {
    login,
    home
}
2)依次创建login.api.js、home.api.js......
login.api.js、home.api.js 差不多
import axios from '@/axios/axios.js'; // 导入axios中创建的axios实例
import baseUrl from '@/axios/base.js'; // 导入接口域名列表
import qs from 'qs'; // 根据需求是否导入qs模块
// qs.parse()是将URL解析成对象的形式
// qs.stringify()是将对象 序列化成URL的形式,以&进行拼接(a=1&b=2)

// JSON.parse() 将JSON 字符串转换为 JavaScript 对象
// JSON.stringify() 将 JavaScript 对象转换为JSON 字符串

const loginService = {
    /**
     * 登录验证账号密码
     * @param {Object} params
     */
    login(params){
        return axios.post(`${baseUrl.ddns}/GisqManagementCloudPlatform/login`,qs.stringify(params));
    }
}

export default loginService;
3)导入到 main.js
main.js
/**
 * 引入-----HTTP库---axios
 * 将 axios 挂载到 vue实例化对象的原型上
 */
import axios from './axios/index.js';
Vue.prototype.$axios = axios;
4)项目中使用
this.$axios.login.login(params).then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

相关文章

网友评论

      本文标题:axios 封装

      本文链接:https://www.haomeiwen.com/subject/tqakrltx.html