如何基于axios封装一个通用的http请求方法?

一个通用的http方法应该有以下功能

(1)请求头携带通用数据,例如token、用户名称等

(2)对响应结果做统一的过滤处理:

①未登录进行登录重定向(有登录要求的系统才需要);

②二进制流数据处理(通常是文件下载)

③请求成功判断

②请求失败通用处理:弹窗提示错误信息(根据选用的组件做UI通用)

实现逻辑:

(1)通过请求拦截器和响应拦截器加上通用的逻辑

(2)如果使用了vue框架的还可以挂在在vue实例上,方便通过 this 访问

 完整代码如下:

import axios from 'axios'

const myAxios = axios.create({
  timeout: 30000, // 超时
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
})

/**
 * 请求拦截器,用于添加统一的请求头
 */
myAxios.interceptors.request.use(function (config) {
  // 添加token
  if (sessionStorage.getItem('token') || localStorage.getItem('token')) { // 添加 token
    config.headers['token'] = sessionStorage.token || localStorage.token
  }
  // 针对环境添加不同的请求头
  if (process.env.NODE_ENV === 'development') {
    config.headers['X-ENNAME'] = 'dev something'
  } else if (process.env.NODE_ENV === 'production') {
    config.headers['X-ENNAME'] = 'prd something'
    config.headers['X-SOMETHING'] = 'prd something'
  }
  return config
}, function (err) {
  showErrToast(err)
  return Promise.reject(err)
})

/**
 * 响应拦截器,对响应状态码做统一的处理,报错给出报错提示
 */
myAxios.interceptors.response.use(function (res) {
  if (res.data.code === 400002) { // 没有登录,登出页面 // (状态码视后端服务而定:表示未登录)前端进行重定向登录,或者后端提供接口,前端直接打开接口,后端自己进行重定向
    window.open('this is login page url or backend service loginout', '_self')
  } else if (res.request.responseType === 'blob') { // 二进制流数据 直接返回
    return res
  } else if (res.status === 200 && res.data.code === 200) { // 请求成功直接抛出数据:成功状态码视后端服务而定
    return res.data
  } else { // 发生错误进行错误提示
    showErrToast(res.data.message || res.statusText)
    return Promise.reject(res.data)
  }
}, function (err) {
  showErrToast(err)
  return Promise.reject(err)
})

/**
 * 请求发生错误时的提示
 * @param {*} e 错误信息
 * 可以自定义,例如使用elementUI的错误提示弹窗 Message({ type: 'error', message: err })
 */
function showErrToast (err) {
  alert(err)
}

export const $http = myAxios

/**
 * 针对vue的封装:对axios的实例重新封装成一个plugin ,方便 Vue.use(xxxx),可以让$http挂在到vue上
 * 通过 this.$http 访问
 */
export default {
  install (Vue, Option) {
    Object.defineProperty(Vue.prototype, '$http', { value: myAxios })
  }
}

/**
 * axios的config配置说明:https://www.axios-http.cn/docs/req_config
 */
// axios.request(config)
// axios.get(url[, config])
// axios.delete(url[, config])
// axios.head(url[, config])
// axios.options(url[, config])
// axios.post(url[, data[, config]])
// axios.put(url[, data[, config]])
// axios.patch(url[, data[, config]])

/**
 * 使用说明
 * 1. 如何挂在到vue上,可以通过 this.$http访问?
 * // main.js
 * import $http from '@/utils/http'
 * Vue.use($http)
 * 
 * 2.如何上传文件?
 * 二进制 'Content-Type': 'application/json'不使用,需要更换请求头headers的content-type
 * 例如:
 *    'Content-Type': 'multipart/form-data'
 *    'Content-Type': 'application/x-www-form-urlencoded'
 * 可以通过config注入自行更换请求头的Content-Type
 * this.$http.request({
    headers: { 'Content-Type': 'multipart/form-data;charset=UTF-8' },
    method: 'post',
    url: '',
    data: formData
  })
 */

当离开A页面,进入B页面时,如何取消A页面进行中的请求,从而避免资源浪费。

axios提供了取消请求的方法   取消请求 | Axios 中文文档 | Axios 中文网

可以在请求拦截器中将每个请求的取消请求方法存储下来,再利用 router.beforeEach 取消请求

这里结合 vuex的store进行存储,当然也可以用别的方式。

import store from '@/store'

const CancelToken = axios.CancelToken // 取消请求

/**
 * 请求拦截器,用于添加统一的请求头
 */
myAxios.interceptors.request.use(config => {
  // 取消请求的方法存入store中
  config.cancelToken = new CancelToken(cancel => {
    store.commit('httpChannel/pushToken', { cancelToken: cancel })
  })
  return config
}, function (err) {
  showErrToast(err)
  return Promise.reject(err)
})

 store如下:

export default {
  namespaced: true,
  state: {
    cancelTokenArr: [] // 取消请求的数组
  },
  getters: {},
  mutations: {
    pushToken (state, payload) {
      state.cancelTokenArr.push(payload.cancelToken)
    },
    clearToken (state) {
      state.cancelTokenArr.forEach(item => {
        if (Object.prototype.toString.call(item) === '[object Function]') {
          item() // 取消请求
        }
      })
      state.cancelTokenArr = []
    }
  },
  actions: {}
}

接下来只需要在路由守卫监听每次页面跳转,跳转前取消pending中的请求

router.beforeEach((to, from, next) => {
  store.commit('httpChannel/clearToken') // 取消请求
  next()
})

上述通用的http封装,发生异常情况的时候会自动showErrToast错误提示。但是在这里,我不希望取消请求也被当成错误提示展示在页面里,所以,还需要进行改造一下:

/**
 * 请求发生错误时的提示
 * @param {*} e 错误信息
 * 可以自定义,例如使用elementUI的错误提示弹窗 Message({ type: 'error', message: err })
 */
function showErrToast (err) {
  if (err !== 'Cancel') {
    Message({ type: 'error', message: err })
  }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值