基于axios二次封装网络请求

本文介绍了基于axios的二次封装,结合vuex、vue-router和element-UI实现网络请求的模块化。特点包括控制loading显示、错误提示、请求处理、多域名支持和接口统一管理。详细阐述了文件目录和功能,以及如何在vue项目中使用和处理断网等异常情况。

基于axios二次封装网络请求

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

请求亮点:

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

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

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

4、请求可以有多个域名

5、请求接口的统一管理

6、封装采用模块化思想

 

一、文件目录:

二、各文件介绍

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>

 

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

撒花完结。。。。。。。

 

 

 

基于 axios 进行二次封装能够让 HTTP 请求的处理更加高效、规范易于维护,避免写法不够简洁、代码量冗余等问题[^1][^2]。以下是一些相关方法示例: ### 二次封装方法概述 - **统一配置**:对请求的基础配置进行统一设置,如基础 URL、请求超时时间等。 - **拦截器设置**:设置请求拦截器响应拦截器,在请求送前响应返回后进行统一处理,例如添加请求头、错误处理等。 - **自定义方法**:根据项目需求,封装一些常用的请求方法,使调用更加简洁。 ### 示例代码 以下是一个简单的 axios 二次封装示例: ```javascript import axios from 'axios'; // 创建一个 axios 实例 const service = axios.create({ baseURL: 'https://api.example.com', // 设置基础 URL timeout: 5000 // 请求超时时间 }); // 请求拦截器 service.interceptors.request.use( config => { // 在请求之前做些什么,例如添加请求头 config.headers['Authorization'] = 'Bearer token'; return config; }, error => { // 处理请求错误 console.log(error); return Promise.reject(error); } ); // 响应拦截器 service.interceptors.response.use( response => { // 对响应数据做点什么 const res = response.data; return res; }, error => { // 处理响应错误 console.log('err' + error); return Promise.reject(error); } ); // 封装常用的请求方法 const request = { get(url, params) { return service.get(url, { params }); }, post(url, data) { return service.post(url, data); }, put(url, data) { return service.put(url, data); }, delete(url, params) { return service.delete(url, { params }); } }; export default request; ``` ### 使用示例 在项目中使用封装好的 axios: ```javascript import request from './utils/request'; // 送 GET 请求 request.get('/api/data', { id: 1 }) .then(response => { console.log(response); }) .catch(error => { console.log(error); }); // 送 POST 请求 request.post('/api/create', { name: 'John' }) .then(response => { console.log(response); }) .catch(error => { console.log(error); }); ``` ### 在 Vue 项目中挂载全局使用 在 Vue 3 项目中,可以将封装好的 axios 挂载到全局: ```javascript import { createApp } from 'vue'; import App from './App.vue'; import request from './utils/request'; const app = createApp(App); app.config.globalProperties.$request = request; app.mount('#app'); ``` 在组件中使用: ```vue <template> <div> <!-- 组件内容 --> </div> </template> <script> export default { mounted() { this.$request.get('/api/data') .then(response => { console.log(response); }) .catch(error => { console.log(error); }); } }; </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值