axios对请求各种异常情况处理的封装方法


Posted in Javascript onSeptember 25, 2018

前端采用了axios来处理网络请求,为了避免在每次请求时都去判断各种各样的网络情况,比如连接超时、服务器内部错误、权限不足等等不一而足,我对axios进行了简单的封装,这里主要使用了axios中的拦截器功能。

封装后的网络请求工具js如下

import axios from 'axios'
import { Toast } from 'mint-ui'
//请求时的拦截
axios.interceptors.request.use(config => {
 return config;
}, err => {
 Toast('请求超时!' );
 return Promise.resolve(err);
})
//响应时的拦截
axios.interceptors.response.use(data => {
 // 返回响应时做一些处理
 // 第一种方式
 const data = response.data

 // 根据返回的code值来做不同的处理(和后端约定)
 switch (data.code) {
  case '0':
   // 举例
   // exp: 修复iPhone 6+ 微信点击返回出现页面空白的问题
   if (isIOS()) {
    // 异步以保证数据已渲染到页面上
    setTimeout(() => {
     // 通过滚动强制浏览器进行页面重绘
     document.body.scrollTop += 1
    }, 0)
   }
   // 这一步保证数据返回,如果没有return则会走接下来的代码,不是未登录就是报错
   return data

  // 需要重新登录
  case 'SHIRO_E5001':
   // 微信生产环境下授权登录
   if (isWeChat() && IS_PRODUCTION) {
    axios.get(apis.common.wechat.authorizeUrl).then(({ result }) => {
     location.replace(global.decodeURIComponent(result))
    })
   } else {
    // 否则跳转到h5登录并带上跳转路由
    const search = encodeSearchParams({
     next: location.href,
    })

    location.replace(`/user/login?${search}`)
   }

   // 不显示提示消息
   data.description = ''
   break

  default:
 }
 // 若不是正确的返回code,且已经登录,就抛出错误
 const err = new Error(data.description)

 err.data = data
 err.response = response

 // 第二种方式,我采取的
 if (data.status && data.status == 200 && data.data.status == 'error') {
  Toast(data.data.msg);
  return data;
 }
 return data;
},err => {
 // 当响应异常时做一些处理
 if (err && err.response) {
  switch (err.response.status) {
   case 400: err.message = '请求错误(400)'; break;
   case 401: err.message = '未授权,请重新登录(401)'; break;
   case 403: err.message = '拒绝访问(403)'; break;
   case 404: err.message = '请求出错(404)'; break;
   case 408: err.message = '请求超时(408)'; break;
   case 500: err.message = '服务器错误(500)'; break;
   case 501: err.message = '服务未实现(501)'; break;
   case 502: err.message = '网络错误(502)'; break;
   case 503: err.message = '服务不可用(503)'; break;
   case 504: err.message = '网络超时(504)'; break;
   case 505: err.message = 'HTTP版本不受支持(505)'; break;
   default: err.message = `连接出错(${err.response.status})!`;
  }
 } else {
  err.message = '连接服务器失败!'
 }
 Toast(err.message);
 return Promise.resolve(err);
})

//如果需要可以封装一些请求的方法
let base = '';

export const postRequest = (url, params) => {
 return axios({
  method: 'post',
  url: `${base}${url}`,
  data: params,
  transformRequest: [function (data) {
   let ret = ''
   for (let it in data) {
    ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
   }
   return ret
  }],
  headers: {
   'Content-Type': 'application/x-www-form-urlencoded'
  }
 });
}
export const uploadFileRequest = (url, params) => {
 return axios({
  method: 'post',
  url: `${base}${url}`,
  data: params,
  headers: {
   'Content-Type': 'multipart/form-data'
  }
 });
}
export const putRequest = (url, params) => {
 return axios({
  method: 'put',
  url: `${base}${url}`,
  data: params,
  transformRequest: [function (data) {
   let ret = ''
   for (let it in data) {
    ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
   }
   return ret
  }],
  headers: {
   'Content-Type': 'application/x-www-form-urlencoded'
  }
 });
}
export const deleteRequest = (url) => {
 return axios({
  method: 'delete',
  url: `${base}${url}`
 });
}
export const get = (url,params) => {
 return axios({
  method: 'get',
  url: `${base}${url}?`,
  params: params,
  headers:{
   'Content-Type': 'application/x-www-form-urlencoded',
   'Access-Token': localStorage.getItem("AccessToken")
  }
 });
}

封装之后的错误信息这个大家一目了然,没啥好说的,唯一要说的是当出错的时候我执行的是:Promise.resolve(err);,而不是Promise.reject(err);

这是什么原因呢?因为封装axios一个重要的目的就是希望能够对错误进行统一处理,不用在每一次发起网络请求的时候都去处理各种异常情况,将所有的异常情况都在工具js中进行统一的处理。但是这种方式也带来一个问题,就是我在发起网络请求的时候,一般都会开启一个进度条,当网络请求结束时,不论请求成功还是失败,我都要将这个进度条关闭掉,而失败的处理我都统一写在工具js里边了,因此就没在请求失败时关闭进度条了,解决这个问题,有两种方案:

1.直接在request的拦截器中开启一个fullscreen的loading,然后在response的拦截器中将其关闭,即我将进度条也封装到工具js中了,但是非常不推荐这种方式,因为这种方式的用户体验非常之差,有兴趣的小伙伴可以自己试一下就知道了。

2.第二种解决方案就是大家看到的,我返回一个Promise.resolve(err),则这个请求不会就此结束,错误的message我已经弹出来了,但是这条消息还是会继续传到then中,也就是说,无论请求成功还是失败,我在成功的回调中都能收到通知,这样我就可以将loading关闭了,比如下面这个登录请求:

var _this = this;
this.loading = true;
this.postRequest('/login', {
 username: this.loginForm.username,
 password: this.loginForm.password
}).then(resp=> {
 _this.loading = false;
 if (resp && resp.status == 200) {
 _this.getRequest("/config/hr").then(resp=> {
  if (resp && resp.status == 200) {
  var data = resp.data;
  _this.$store.commit('login', data);
  var path = _this.$route.query.redirect;
  _this.$router.replace({path: path == '/' || path == undefined ? '/home' : path});
  }
 })
 }

添加Vue插件

由于我对axios进行了封装,因此在每一个需要使用axios的地方,都需要导入相应的请求,略显麻烦,参考https://cn.vuejs.org/v2/guide/plugins.html,我将请求方法挂到Vue上,具体操作如下:

1.在main.js中导入所有的请求方法,如下:

import {get} from './utils/api'
import {postRequest} from './utils/api'
import {deleteRequest} from './utils/api'
import {putRequest} from './utils/api'

2.把它们添加到 Vue.prototype 上,如下:

Vue.prototype.getRequest = getRequest;
Vue.prototype.postRequest = postRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.putRequest = putRequest;

如此之后,以后再需要发送网络请求,就不需要导入api了,直接通过下面这种方式即可:

Post方法:

this.postRequest('/login', {
 username: this.loginForm.username,
 password: this.loginForm.password
}).then(resp=> {
 ...
 }
});

GET方法:

_this.get(
   this.url_s+"/Notice/findTotalCount",{
    userId:localStorage.getItem("userid"),
    openId: localStorage.getItem('openId')
   }
  )
  .then(function(res) {
   //
  })

以上这篇axios对请求各种异常情况处理的封装方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
自己的js工具_Form 封装
Aug 21 Javascript
Jquery选择子控件"大于号"和" "区别介绍及使用示例
Jun 25 Javascript
实现checkbox全选、反选、取消JavaScript小脚本异常
Apr 10 Javascript
jQuery搜索子元素的方法
Feb 10 Javascript
Javascript HTML5 Canvas实现的一个画板
Apr 12 Javascript
jquery中取消和绑定hover事件的实现代码
Jun 02 Javascript
Node.js中使用mongoose操作mongodb数据库的方法
Sep 12 Javascript
使用Vuex实现一个笔记应用的方法
Mar 13 Javascript
jQuery实现的网站banner图片无缝轮播效果完整实例
Jan 28 jQuery
vue数据初始化initState的实例详解
Apr 11 Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
Aug 09 Javascript
VuePress 中如何增加用户登录功能
Nov 29 Javascript
解决vue axios的封装 请求状态的错误提示问题
Sep 25 #Javascript
angular 数据绑定之[]和{{}}的区别
Sep 25 #Javascript
Vue高版本中一些新特性的使用详解
Sep 25 #Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
Sep 25 #Javascript
vue实现多个元素或多个组件之间动画效果
Sep 25 #Javascript
vue 音乐App QQ音乐搜索列表最新接口跨域设置方法
Sep 25 #Javascript
Vue页面跳转动画效果的实现方法
Sep 23 #Javascript
You might like
PHP中source #N问题的解决方法
2014/01/27 PHP
php实现字符串首字母转换成大写的方法
2015/03/17 PHP
php利用递归实现删除文件目录的方法
2016/09/23 PHP
jQuery 幻灯片插件(带缩略图功能)
2011/01/24 Javascript
js的Prototype属性解释及常用方法
2014/05/08 Javascript
全面解析Bootstrap表单使用方法(表单控件状态)
2015/11/24 Javascript
深入浅析NodeJs并发异步的回调处理
2015/12/21 NodeJs
AngularJS基础 ng-list 指令详解及示例代码
2016/08/02 Javascript
轻松实现js选项卡切换效果
2016/09/24 Javascript
微信小程序 Buffer缓冲区的详解
2017/07/06 Javascript
不得不看之JavaScript构造函数及new运算符
2017/08/21 Javascript
Layui实现数据表格中鼠标悬浮图片放大效果,离开时恢复原图的方法
2019/09/11 Javascript
原生js实现随机点名功能
2019/11/05 Javascript
JS call()及apply()方法使用实例汇总
2020/07/11 Javascript
vue 路由缓存 路由嵌套 路由守卫 监听物理返回操作
2020/08/06 Javascript
element 动态合并表格的步骤
2020/12/31 Javascript
Python中的choice()方法使用详解
2015/05/15 Python
Python利用ElementTree模块处理XML的方法详解
2017/08/31 Python
Python探索之创建二叉树
2017/10/25 Python
Python操作word常见方法示例【win32com与docx模块】
2018/07/17 Python
Python操作MySQL数据库的两种方式实例分析【pymysql和pandas】
2019/03/18 Python
python设置环境变量的原因和方法
2019/06/24 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
python飞机大战pygame游戏背景设计详解
2019/12/17 Python
Python 音频生成器的实现示例
2019/12/24 Python
浅谈Html5多线程开发之WebWorkers
2018/05/02 HTML / CSS
萌新HTML5 入门指南(二)
2020/11/09 HTML / CSS
H&M美国官网:欧洲最大的服饰零售商
2016/09/07 全球购物
美国基督教约会网站:ChristianCafe.com
2020/02/04 全球购物
幼儿园校车司机的岗位职责
2014/01/30 职场文书
素食餐饮项目创业计划书
2014/02/02 职场文书
教师年度考核评语
2014/04/28 职场文书
卫生院艾滋病宣传活动小结
2014/07/09 职场文书
入党积极分子学习优秀共产党员先进事迹思想汇报
2014/09/13 职场文书
先进事迹材料怎么写
2014/12/30 职场文书
初一军训感言
2015/08/01 职场文书