基于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>
本文借鉴了一些大佬的文章,灵感更多的是自己项目经验的总结,若有问题还请大佬指出!
撒花完结。。。。。。。
posted on 2020-08-31 14:35 Pending1126 阅读(310) 评论(0) 收藏 举报
浙公网安备 33010602011771号