欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于axios二次封装网络请求

程序员文章站 2024-03-07 14:40:57
...

基于axios二次封装网络请求

本套网络请求基于axios的二次封装,用到了vuex(断网及其他错误的标识)、vue-router(页面跳转)和element-UI的一些交互;封装采用模块化思想,各个文件的功能单一,大大降低了耦合性。

请求亮点:

1、可控制请求时loading的样式及是否需要显示loading;

2、请求错误时的统一提示

3、请求超时、断网、请求报错的统一处理

4、请求可以有多个域名

5、请求接口的统一管理

6、封装采用模块化思想

 

一、文件目录:

基于axios二次封装网络请求

二、各文件介绍

1、/http/axios.js

 

import axios from "axios"
import httpCode from './httpCode';
import router from '../router/index';
import store from '../store/index';

//创建axios实例
var instance = axios.create({ timeout: 1000 * 20 });

// 请求拦截器
instance.interceptors.request.use(
    config => {
        // 登录流程控制中 根据本地是否存在token判断用户的登录情况
        const token = store.state.token;
        token && (config.headers.Authorization = token);
        return config;
    },
    error => Promise.error(error)
)

// 响应拦截器
instance.interceptors.response.use(
    // 请求成功
    res => {
        res.status === 200 ? Promise.resolve(res) : Promise.reject(res)
        //请求成功后改变network状态为true
        store.dispatch('changeNetwork', true);
    },
    // 请求失败
    error => {
        const { response } = error;
        if (response) {
            //请求已发出 不在2xx的范围
            httpCode(response.status)
            return Promise.reject(response);
        } else {
            //处理断网的情况 请求超时或断网时 更新state的network状态
            router.push({ path: '/network' })
            //请求失败后改变network状态为false
            store.dispatch('changeNetwork', false);
        }
    });

export default instance

2、/http/httpCode.js

import router from '../router/index';
import store from '../store/index';
import { Notification } from 'element-ui';

/** 
 * 跳转登录页
 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
 */
const toLogin = () => {
    router.replace({
        path: '/login',
        query: {
            redirect: router.currentRoute.fullPath
        }
    });
}

/** 
 * 跳转404页面
 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
 */
const to404Error = () => {
    router.replace({
        name: '404Error',
        query: {
            redirect: router.currentRoute.fullPath
        }
    });
}

/** 
 * 请求失败后的错误统一处理 
 * @param {请求失败的状态码} status
 */
export default function (code) {
    // 请求错误信息
    let errorInfo = ''
    //判断参数来输出错误信息
    switch (code) {
        case 400:
            errorInfo = "错误请求";
            break;
        case 401:
            //跳转到登录页
            toLogin();
            errorInfo = '访问令牌无效或已过期';
            break;
        case 403:
            //拒绝时的参数
            localStorage.removeItem('token');
            store.dispatch('loginSuccess', null);
            setTimeout(() => {
                toLogin();
            }, 1000);
            errorInfo = '登录过期,请重新登录';
            break;
        case 404:
            to404Error()
            errorInfo = '请求资源不存在';
            break;
        case 405:
            errorInfo = '请求方法未允许';
            break;
        case 408:
            errorInfo = '请求超时';
            break;
        case 500:
            errorInfo = '访问服务失败';
            break;
        case 501:
            errorInfo = '未实现';
            break;
        case 502:
            errorInfo = '无效网关';
            break;
        case 503:
            errorInfo = '服务不可用';
            break;
        default:
            errorInfo = "连接错误";
            break;
    }
    Notification.error({
        title: "提示",
        message: errorInfo
    })
}

3、/http/base.js

/**
 * 域名统一管理
 */

//测试域名
export const testUrl = "https://abnercapi.cdcyy.net"

//正式域名
export const path = "https://abnercapi.cdcyy.net"

4、/http/index.js

import axios from './axios';
import { Loading } from 'element-ui';
import { Notification } from 'element-ui';

//Loading 参数
let obj = {
    lock: true,
    text: '加载中...',
    target: "#main",
    spinner: 'el-icon-loading'
}

/**
 * POST请求
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @param {其他参数,第一项为是否需要Loading} params2
 */
export const post = function (url, params, ...params2) {
    if (params2 && params2.length === 0) {
        //当未传入其他参数时 默认有loading 且默认loading下方的文字文默认“加载中...”
        return request("POST", url, params, true)
    } else if (params2[0].isLoading) {
        //当传入其他参数时 第一个参数的第一项为是否需要loading 当“isLoading”字段为“true”时 默认需要更换loading下方的文字”
        obj.text = params2[0].loadingText ? params2[0].loadingText : "加载中..."
        return request("POST", url, params, true)
    } else {
        //当传入其他参数时 其他情况一律处理为不要loading
        return request("POST", url, params, true)
    }
}

/**
 * GET请求
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @param {其他参数,第一项为是否需要Loading} params2
 */
export const get = function (url, params, ...params2) {
    if (params2 && params2.length === 0) {
        //当未传入其他参数时 默认有loading 且默认loading下方的文字文默认“加载中...”
        return request("GET", url, params, true)
    } else if (params2[0].isLoading) {
        //当传入其他参数时 第一个参数的第一项为是否需要loading 当“isLoading”字段为“true”时 默认需要更换loading下方的文字”
        obj.text = params2[0].loadingText ? params2[0].loadingText : "加载中..."
        return request("GET", url, params, true)
    } else {
        //当传入其他参数时 其他情况一律处理为不要loading
        return request("GET", url, params, true)
    }
}

/**
 * 网络请求
 * @param {请求方法} method
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @param {loading状态} status 
 */
function request(method, url, params, status) {
    let loading
    if (status) {
        loading = Loading.service(obj);
    }
    return new Promise((resolve, reject) => {
        axios({
            method: method,
            url: url,
            data: params
        })
            .then(res => {
                //停止Loading
                if (status) loading.close();
                //返回数据的操作 可根据后台返回的数据结构自行处理
                if (res && res.data && res.data.status) {
                    resolve(res.data)
                } else {
                    resolve(false)
                    Notification({
                        title: "提示",
                        message: res.data.message,
                        type: "error"
                    })
                }
            })
            .catch(err => {
                //停止Loading
                if (status) loading.close();
                reject(err)
            })
    })
}

 

5、/api/orderReq.js

/*
 * 订单模块接口列表
 */
import { testUrl } from '@/http/base'; // 导入接口域名列表
import { post, get } from '@/http/index'; // 导入http中创建的axios实例
import qs from 'qs'; //参数序列化 qs.stringify(params)

const order = {
    //获取列表
    getList(params) {
        //loading参数配置
        let loadOpt = { isLoading: true, loadingText: "我要加载..." }
        return post(`${testUrl}xxxxxxx`, {}, loadOpt);
    },
    //更新
    updataList(params) { },
    //删除列表
    delectList(params) { },
    //添加列表
    setList(params) { },
}

export default order;

6、/api/index.js

/**
 * 接口统一管理
 */
import order from '@/api/orderReq';


export default {
    order,
}

三、挂载到vue原型上

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import api from './api/index'

Vue.prototype.$api = api;
Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: function (h) { return h(App) }
}).$mount('#app')

四、页面使用(例)

this.$api.order.getList(obj).then((res) => {
        console.log(res);
        });

五、断网处理页面

<template>
  <div class="container">
    <h3>我没网了</h3>
    <el-button type="primary" @click="onRefresh()">刷新</el-button>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  name: "App",
  inject: ["reload"],
  computed: {
    ...mapGetters(["getNetwork"]),
  },
  created() {
    //当请求成功就不能到该页面
    if (this.getNetwork) this.$router.go(-1);
  },
  methods: {
    //返回之前的页面再请求一次判断是否请求成功
    onRefresh() {
      this.$router.go(-1);
    },
  },
};
</script>
<style lang="less" scoped>
.container {
  text-align: center;
}
</style>

六、404页面

<template>
  <div class="container">
    <h3>我TM居然是一个没人要的页面</h3>
    <el-button type="primary" @click="$router.push('/home')">返回首页</el-button>
    <el-button type="primary" @click="onRefresh()">刷新</el-button>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  name: "App",
  inject: ["reload"],
  computed: {
    ...mapGetters([""]),
  },
  methods: {
    //返回之前的页面再请求一次判断是否请求成功
    onRefresh() {
      this.$router.go(-1);
    },
  },
};
</script>
<style lang="less" scoped>
.container {
  text-align: center;
}
</style>

 

本文借鉴了一些大佬的文章,灵感更多的是自己项目经验的总结,若有问题还请大佬指出!

撒花完结。。。。。。。