《程序猿入职必会(7) · 前端请求工具封装》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍

CSDN.gif

写在前面的话

前篇博文介绍了,前后端分离实战项目中,关于统一返回结果的封装。
本篇博文就接着介绍一下,前端 Axios 插件封装思路,以及对于这一返回封装结果的接受处理。
加油,程序猿,保持住Tempo,开干,玩的就是真实!

关联文章:
《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》
《程序猿入职必会(2) · 搭建具备前端展示效果的 Vue》
《程序猿入职必会(3) · SpringBoot 各层功能完善 》
《程序猿入职必会(4) · Vue 完成 CURD 案例 》
《程序猿入职必会(5) · CURD 页面细节规范 》
《程序猿入职必会(6) · 返回结果统一封装》


前端请求工具封装

封装思路

Vue 项目中,可以使用的请求插件很多,这边选用之前已整合完毕的 Axios 展开说明,其他技术类似。
前端请求工具类应该具备哪些特性?

  • 提取所有请求的公用部分,例如后端服务前缀、超时时间、公用请求头等
  • 具备请求前置拦截逻辑,可以针对请求头和参数进行封装,也可以做前端鉴权动作
  • 具备请求后置拦截逻辑,可以针对响应内容进行解析处理,针对不同状态码做出不同应对
  • 对外提供丰富便捷的调用方法,方便页面和组件快速使用

实例 Demo

这里先基于上述的封装思路,展示一段已实现的效果,再拆分说明。

【封装工具类】

/**
 * Http 请求封装工具类
 * Axios是基于http客户端的promise,面向浏览器和NodeJS
 * Created by LinWang on 2020/08/08.
 */
import axios from 'axios'
import qs from 'qs'
import store from '../store'
import { Message, MessageBox } from 'element-ui'
import { getToken } from '@/utils/auth'
import _ from 'lodash'
import { showFullScreenLoading, tryHideFullScreenLoading } from './loadService'

/**
 * 创建Axios实例
 */
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, timeout: process.env.TIME_OUT
})
service.all = axios.all
service.spread = axios.spread

/**
 * 添加一个请求拦截器(前置)
 */
service.interceptors.request.use(config => {
  showFullScreenLoading()
  if (_.isObject(config.data)) {
    config.data = qs.stringify(config.data, { allowDots: true })
  }
  config.headers['Content-Type'] = 'application/x-www-form-urlencoded' // 默认为 application/json
  config.headers.operator = getToken() // 让每个请求携带自定义token,请根据实际情况自行修改
  config.headers.requestId = new Date().getTime() // 请求时间点
  return config
}, error => {
  console.log(error)
  Promise.reject(error)
})

/**
 * 添加一个返回拦截器(后置处理)
 */
service.interceptors.response.use(response => {
  tryHideFullScreenLoading()
  const res = response.data
  if (response.status !== 200 || !res.success) {
    Message({
      message: res.message, type: 'warning', duration: 5 * 1000
    })
    // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
    if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
      MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
        confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning'
      }).then(() => {
        store.dispatch('FedLogOut').then(() => {
          location.reload() // 为了重新实例化vue-router对象 避免bug
        })
      })
    }
    return Promise.reject(res)
  } else {
    return res.data
  }
}, error => {
  tryHideFullScreenLoading()
  console.log('err' + error)
  Message({
    message: error.error, type: 'warning', duration: 5 * 1000
  })
  return Promise.reject(error)
})

export default service

【框架整合工具类】

Tips:就main.js添加两行代码即可,$http是添加到全局,可以快速使用

import http from '@/utils/request'
Vue.prototype.$http = http

【某个实体对应 api.js - 代码生成】

import request from '@/utils/request'

export default {
  getList(params) {
    return request({
      url: '/zyTeacherInfo/', method: 'get', params
    })
  },

  get(params) {
    return request({
      url: '/zyTeacherInfo/' + params.teaCode, method: 'get', params
    })
  },

  getPage(params) {
    return request({
      url: '/zyTeacherInfo/page', method: 'get', params
    })
  },

  update(params) {
    return request({
      url: '/zyTeacherInfo/update', method: 'post', params
    })
  },

  insert(params) {
    return request({
      url: '/zyTeacherInfo/insert', method: 'post', params
    })
  },

  remove(params) {
    return request({
      url: '/zyTeacherInfo/delete', method: 'post', params
    })
  }
}

【页面使用示例】

// 引入api.js
import ZyTeacherInfoApi from '@/api/study/ZyTeacherInfoApi'

// 通过实体对应api.js,触发删除逻辑
handleDelete(row) {
  let that = this
  ZyTeacherInfoApi.remove({ teaCode: row.teaCode }).then(() => {
    this.$notify({
      title: '成功',
      message: '删除成功',
      type: 'success',
      duration: 1000,
      onClose() {
        that.fetchData()
      }
    })
  })
},

// 利用工具类的all方法,并联查询多个接口
this.$http.all([ZyTeacherInfoApi.getPage(this.listQuery)])
  .then(this.$http.spread(function(perms) {
    that.list = perms.rows
    that.total = perms.total
    that.listLoading = false
  }))

细节说明

【基础 Axios】
整个请求工具类的核心就是 Axios。
使用 axios.create 创建一个 Axios 实例,然后设置后端服务前缀、超时时间等,这些属性都配置再项目配置文件中。
将 axios.all 和 axios.spread,添加到上述实例,方便快速复用。
代码段参考:

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, timeout: process.env.TIME_OUT
})
service.all = axios.all
service.spread = axios.spread

【添加 Axios 请求拦截器】
利用 service.interceptors.request.use 添加请求拦截器,里面按如下步骤执行:

  • 显示全屏 Loading 效果,这个是自己封装的,也可以采用外部插件;
  • 设置 Content-Type,按指定的入参类型组装参数;
  • 设置操作人、时间戳等其他请求头信息;
service.interceptors.request.use(config => {
  showFullScreenLoading()
  if (_.isObject(config.data)) {
    config.data = qs.stringify(config.data, { allowDots: true })
  }
  config.headers['Content-Type'] = 'application/x-www-form-urlencoded' // 默认为 application/json
  config.headers.operator = getToken() // 让每个请求携带自定义token,请根据实际情况自行修改
  config.headers.requestId = new Date().getTime() // 请求时间点
  return config
}, error => {
  console.log(error)
  Promise.reject(error)
})

【添加 Axios 响应拦截器】
利用 service.interceptors.request.use 添加请求拦截器,里面按如下步骤执行:

  • 响应成功和失败,都需要关闭 Loading 效果;
  • 根据 code 状态码判断失败与否;
  • 如果是成功的话,将数据返回给调用方;
  • 如果是报错的话,返回报错信息给调用发,同时利用提示信息组件,展示提示;
service.interceptors.response.use(response => {
  tryHideFullScreenLoading()
  const res = response.data
  if (response.status !== 200 || !res.success) {
    Message({
      message: res.message, type: 'warning', duration: 5 * 1000
    })
    // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
    if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
      MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
        confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning'
      }).then(() => {
        store.dispatch('FedLogOut').then(() => {
          location.reload() // 为了重新实例化vue-router对象 避免bug
        })
      })
    }
    return Promise.reject(res)
  } else {
    return res.data
  }
}, error => {
  tryHideFullScreenLoading()
  console.log('err' + error)
  Message({
    message: error.error, type: 'warning', duration: 5 * 1000
  })
  return Promise.reject(error)
})

总结陈词

此篇文章介绍了前端 Axios 插件封装思路,仅供学习参考。
Axios 官网用法很多,丰富多彩,但实战中,上述提供的示例已经覆盖了大部分常用用法了。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

CSDN_END.gif

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

战神刘玉栋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值