React + TS + mock 的Axios封装

1,460 阅读3分钟

1.背景

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中.我封装了一个轻量级的ts+ axios,采用mockjs去模拟数据的返回,功能不算复杂,可在这基础上加入自己需要的拦截或数据处理。

官网链接

特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

优势

axios已经是一个比较完善的api,可以根据官网的方法传入method,data,url等直接在回调then()中对返回数据进行处理。但由于http请求的频繁调用,对请求中的配置进行封装是一件既能简化代码也能节约重复代码的必须操作,如header加入token,返回码的分类处理等。

// 直接调用
axios({   
    method: 'post',   
    url: '/user/12345',   
    data: {firstName: 'Fred', lastName: 'Flintstone'} 
}).then( response => {
    console.log(response)
});

封装可做的五点拦截/处理

1.请求拦截
2.回调拦截
3.token或cookie
4.重复请求拦截
5.文件流处理

2.实现步骤

  1. 安装 npm

npm install axios
  1. 封装成request.ts

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { message } from 'antd'
// import qs from 'qs'

const service: AxiosInstance = axios.create({
  baseURL: process.env.BASEURL_API,
  timeout: 10000,
  // withCredentials: true, // 允许把cookie传递到后台
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
  // 如果content-Type 是 "application/x-www-form-urlencoded" 需要对 data 进行字符转义
  // transformRequest: [
  //   (data, headers) => {
  //     return qs.stringify(data)
  //   }
  // ]
})

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    // 对响应数据进行处理
    const { data, headers } = response
    if (headers.authorization) {
      // 判断是否授权
      localStorage.setItem('Bear_Token', headers.authorization)
    } else {
      if (data?.token) {
        // 另一种情况token放在返回data中
        localStorage.setItem('Bear_Token', data.token)
      }
    }
    switch (data.status) {
      case 808:
        message.error('该用户已被冻结,请联系工作人员')
        break
      case 504:
        message.error('网络超时')
        break
      default:
        message.info(data.message)
    }
    return response.data
  },
  (error) => {
    const { response } = error
    if (response) {
      message.error(error.message)
      return Promise.reject(error)
    } else {
      message.error('网络连接异常,请稍后再试!')
    }
  }
)
// 请求拦截器
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    const token = localStorage.getItem('Bear_Token')
    const { headers } = config
    if (token && headers) headers.Authorization = `Bearer ${token}` // 增加header作为判断,因改版本的headers定义不包含undefined会报错
    // 请求之前做些什么
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

export { service as axios }

  • 引入了typescript,在axios中直接引入type去声明request,response,实例的类型
  • 在创建实例的axios.create中声明了url,timeout最大延时,header
  • content-type使用了最普及的application/json;charset=utf-8,即使用json格式与服务端通讯
  • 如果content-Type 是 "application/x-www-form-urlencoded" 需要对 data 使用qs库字符转义
  • 在请求拦截中,从localStorage中获取token插入到header.Authorization中
  • 在响应拦截中,把token存储在localStorage中,并根据响应码进行不同的处理
  1. user.ts 把api放在api文件夹下统一管理

import { axios } from '@/utils/request'

export interface LoginParam {
  username: string
  password: string
}

export const Login = (param: LoginParam) => {
  return axios({
    url: '/user/login',
    method: 'post',
    data: param
  })
}

利用封装好的axios写了一个登陆的接口,暴露给组件调用

  1. mock 生成模拟数据

import Mock from 'mockjs'
const Random = Mock.Random
const userInfo = Mock.mock('/user/login', 'post', () => {
  const ret = Mock.mock({ username: '@cname', age: Random.integer(60, 100), ID: Random.id() })
  return {
    status: 808,
    data: ret
  }
})

export { userInfo }

关于Mockjs,在调用接口的组件文件中引入,就会自动被mockjs拦截并返回Mock模拟的数据

  1. index.tsx 关键代码

import { Login, LoginParam } from '@/api/user'
import '@/../mock/user' 

...
    const onFinish = (values: LoginParam) => {
    message.loading('登陆中').then(() => {
      Login(values).then((res) => {
        if (res.status === 200) {
          message.destroy()
          message.success('欢迎回来')
          navigate('/') // 跳转到首页
        }
      })
      })

由于封装好对response的处理,在res.status !== 200的情况下,会自动根据配置好的信息提示用户。 同时,在成功登录后,可把用户信息存放在localStorage或状态管理中。在用户异常时,也可以执行退出登录的方法和跳转回登录页面。

结语

关于Axios的封装并没有固定的模板,也可加入拦截重复请求或处理文件流等更多功能。最重要是根据自己的需求去封装,无需尽可能地加入不必要的功能。