Vue + TypeScript 实战(六)axios封装

1、安装

yarn add axios

2、 通用功能

  • 正常请求该有的(跨域携带cookie,token,超时设置)
  • 请求响应拦截器
  • 取消重复请求
  • 响应状态封装
  • 解除重复请求锁定
  • 取消请求
  • 封装请求方法

3、功能实现

3.1 基础封装

axios设置拦截器:拦截每次请求和响应,简单使用方法如下:

  • axios.interceptors.request.use(请求成功拦截, 请求失败拦截)
  • axios.interceptors.response.use(响应成功拦截, 响应失败拦截)
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

// 创建axios实例
export const axiosInstance: AxiosInstance = axios.create({
  baseURL: 'http://localhost:8080/', // 基础路径
  timeout: 60 * 1000  //超时配置
})

// 请求拦截器
axiosInstance.interceptors.request
  .use((config: AxiosRequestConfig) => {
    // 在发送请求之前做些什么
    return config
  },(error:any) => {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 响应拦截器
axiosInstance.interceptors.response
  .use((response: AxiosResponse) => {
       // 对响应数据做点什么
      return response
    },(error:any) => {
    // 对响应错误做点什么
  return Promise.reject(error)
})

3.2 取消重复请求

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import {MessageType} from "element-ui/types/message";
import {Message} from "element-ui";

// 创建axios实例
export const axiosInstance: AxiosInstance = axios.create({
  baseURL: 'http://localhost:8080/', // 基础路径
  timeout: 60 * 1000  //超时配置
})


/**
 * toast提示
 * @param message
 * @param type
 */
function dialog (type: MessageType, message = '') {
  return Message({
    message,
    type,
    duration: 5000,
    showClose: true
  })
}

// 记录正在请求的接口
// 每次请求前都会把path放在此数组中,响应成功后清除此请求path
let listenPendingAjax: any = {} // 对应字段为true说明已有该请求,还未结束

// 请求拦截器
axiosInstance.interceptors.request
  .use((config: AxiosRequestConfig) => {
    if (!config.url) {
      return Promise.reject({
        isCancel: true,
        message: 'no url'
      })
    } else if (listenPendingAjax[config.url]) { // 拦截重复请求,为false时不做处理
      return Promise.reject({
        url: config.url,
        isCancel: true,
        message: '重复请求!'
      })
    } else if (!listenPendingAjax[config.url]) { // 正常请求
      if (!config.cancelToken) {
        const source = axios.CancelToken.source()
        config.cancelToken = source.token
        listenPendingAjax[config.url] = source
      } else {
        listenPendingAjax[config.url] = config.cancelToken
      }
    }
    return config
  },(error:any) => {
  return Promise.reject(error)
})

// 响应拦截器
axiosInstance.interceptors.response
  .use((response: AxiosResponse) => {
    if (response.config.url) {
      delete listenPendingAjax[response.config.url]
    }
      return response
    },(error:any) => {
    if (error.url && typeof error.url === 'string') {
      delete listenPendingAjax[error.url]
    } else { // 发生未知错误
      listenPendingAjax = {}
    }
  return Promise.reject(error)
})

3.3 响应状态封装

// 响应拦截器
axiosInstance.interceptors.response
  .use((response: AxiosResponse) => {
    if (response.config.url) {
      delete listenPendingAjax[response.config.url]
    }
      return response
    },(error:any) => {
    if (error.url && typeof error.url === 'string') {
      delete listenPendingAjax[error.url]
    } else { // 发生未知错误
      listenPendingAjax = {}
    }

    axios.isCancel(error) && console.log('Request canceled: ' + error)
    if (error.code === 'ECONNABORTED') {
      error.message = '系统繁忙,请稍候再试'
    }
    if (/timeout/.test(error.message)) {
      error.message = '系统超时,请稍候再试'
    }
    if (error.message === 'Network Error') {
      error.message = '网络错误,请检查网络情况'
    }
    error.message && dialog('error', error.message)
  return Promise.reject(error)
})

3.4 封装请求方法

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import {MessageType} from "element-ui/types/message";
import {Message} from "element-ui";
import qs from "qs";

// 创建axios实例
export const axiosInstance: AxiosInstance = axios.create({
  baseURL: 'http://localhost:8080/', // 基础路径
  timeout: 60 * 1000  //超时配置
})


/**
 * toast提示
 * @param message
 * @param type
 */
function dialog (type: MessageType, message = '') {
  return Message({
    message,
    type,
    duration: 5000,
    showClose: true
  })
}

// 记录正在请求的接口
// 每次请求前都会把path放在此数组中,响应成功后清除此请求path
let listenPendingAjax: any = {} // 对应字段为true说明已有该请求,还未结束

// 请求拦截器
axiosInstance.interceptors.request
  .use((config: AxiosRequestConfig) => {
    if (!config.url) {
      return Promise.reject({
        isCancel: true,
        message: 'no url'
      })
    } else if (listenPendingAjax[config.url]) { // 拦截重复请求,为false时不做处理
      return Promise.reject({
        url: config.url,
        isCancel: true,
        message: '重复请求!'
      })
    } else if (!listenPendingAjax[config.url]) { // 正常请求
      if (!config.cancelToken) {
        const source = axios.CancelToken.source()
        config.cancelToken = source.token
        listenPendingAjax[config.url] = source
      } else {
        listenPendingAjax[config.url] = config.cancelToken
      }
    }
    return config
  },(error:any) => {
  return Promise.reject(error)
})

// 响应拦截器
axiosInstance.interceptors.response
  .use((response: AxiosResponse) => {
    if (response.config.url) {
      delete listenPendingAjax[response.config.url]
    }
      return response
    },(error:any) => {
    if (error.url && typeof error.url === 'string') {
      delete listenPendingAjax[error.url]
    } else { // 发生未知错误
      listenPendingAjax = {}
    }
  return Promise.reject(error)
})


/**
 * 定义request类
 * 封装请求方法
 */

export default class ServerRequest {
  modulePath: string
  nativeAxios: AxiosInstance

  /**
   * Api构造函数
   * @param modulePath{string}
   */
  constructor (modulePath: string) {
    this.modulePath = modulePath
    this.nativeAxios = axiosInstance
  }

  /**
   * 获取调用api时整合出的url地址
   * @param url{string}
   * @returns {*}
   */
  getModulePathUrl (url: string): string {
    return /^https?:\/\//.test(url) ? url : this.modulePath + url
  }


  /**
   * axios的request方法
   * @param options{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  request (options: AxiosRequestConfig): Promise<AxiosResponse> {
    options.url = this.getModulePathUrl(options.url || '')
    return this.nativeAxios(options)
  }

  /**
   * get请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  get (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.get(this.getModulePathUrl(url), config)
  }

  /**
   * post请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  post (url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.post(this.getModulePathUrl(url), data, config)
  }

  /**
   * put请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  put (url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.put(this.getModulePathUrl(url), data, config)
  }

  /**
   * delete请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  delete (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.delete(this.getModulePathUrl(url), config)
  }

  /**
   * head请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  head (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.delete(this.getModulePathUrl(url), config)
  }

  /**
   * patch请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  patch (url: string, data: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.patch(this.getModulePathUrl(url), data, config)
  }
}

3.5 解除重复请求锁定

  /**
   * 解除重复请求锁定,可以多次请求,解除可能会出现数据展示错乱的情况
   * @param url{string}
   * @returns {ServerRequest}
   */
  unlock (url: string): ServerRequest {
    listenPendingAjax[this.getModulePathUrl(url)] = false
    return this
  }

3.6 取消上一次请求,能保证数据是后面的请求返回的

  /**
   * 取消上一次请求,能保证数据是后面的请求返回的
   * @param url
   * @param params
   */
  cancel (url: string, params?: any): ServerRequest {
    if (params) {
      const urlSearch = url.replace(/#.*$/, '').split('?')[1]
      const urlHash = url.split('#')[1] ? '#' + url.split('#')[1] : ''
      urlSearch && Object.assign(params, qs.parse(urlSearch))
      url = url.split('?')[0] + '?' + qs.stringify(params) + urlHash
    }
    const resUrl = this.getModulePathUrl(url)
    if (listenPendingAjax[resUrl]) {
      listenPendingAjax[resUrl].cancel()
      listenPendingAjax[resUrl] = undefined
    }
    return this
  }

3.7 完整代码

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import {MessageType} from "element-ui/types/message"
import {Message} from "element-ui"
import qs from "qs"

// 创建axios实例
export const axiosInstance: AxiosInstance = axios.create({
  baseURL: 'http://localhost:8080/', // 基础路径
  timeout: 60 * 1000  //超时配置
})


/**
 * toast提示
 * @param message
 * @param type
 */
function dialog (type: MessageType, message = '') {
  return Message({
    message,
    type,
    duration: 5000,
    showClose: true
  })
}

// 记录正在请求的接口
// 每次请求前都会把path放在此数组中,响应成功后清除此请求path
let listenPendingAjax: any = {} // 对应字段为true说明已有该请求,还未结束

// 请求拦截器
axiosInstance.interceptors.request
  .use((config: AxiosRequestConfig) => {
    if (!config.url) {
      return Promise.reject({
        isCancel: true,
        message: 'no url'
      })
    } else if (listenPendingAjax[config.url]) { // 拦截重复请求,为false时不做处理
      return Promise.reject({
        url: config.url,
        isCancel: true,
        message: '重复请求!'
      })
    } else if (!listenPendingAjax[config.url]) { // 正常请求
      if (!config.cancelToken) {
        const source = axios.CancelToken.source()
        config.cancelToken = source.token
        listenPendingAjax[config.url] = source
      } else {
        listenPendingAjax[config.url] = config.cancelToken
      }
    }
    return config
  },(error:any) => {
  return Promise.reject(error)
})

// 响应拦截器
axiosInstance.interceptors.response
  .use((response: AxiosResponse) => {
    if (response.config.url) {
      delete listenPendingAjax[response.config.url]
    }
      return response
    },(error:any) => {
    if (error.url && typeof error.url === 'string') {
      delete listenPendingAjax[error.url]
    } else { // 发生未知错误
      listenPendingAjax = {}
    }

    axios.isCancel(error) && console.log('Request canceled: ' + error)
    if (error.code === 'ECONNABORTED') {
      error.message = '系统繁忙,请稍候再试'
    }
    if (/timeout/.test(error.message)) {
      error.message = '系统超时,请稍候再试'
    }
    if (error.message === 'Network Error') {
      error.message = '网络错误,请检查网络情况'
    }
    error.message && dialog('error', error.message)
  return Promise.reject(error)
})


/**
 * 定义request类
 * 封装请求方法
 */

export default class ServerRequest {
  modulePath: string
  nativeAxios: AxiosInstance

  /**
   * Api构造函数
   * @param modulePath{string}
   */
  constructor (modulePath: string) {
    this.modulePath = modulePath
    this.nativeAxios = axiosInstance
  }

  /**
   * 获取调用api时整合出的url地址
   * @param url{string}
   * @returns {*}
   */
  getModulePathUrl (url: string): string {
    return /^https?:\/\//.test(url) ? url : this.modulePath + url
  }


  /**
   * axios的request方法
   * @param options{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  request (options: AxiosRequestConfig): Promise<AxiosResponse> {
    options.url = this.getModulePathUrl(options.url || '')
    return this.nativeAxios(options)
  }

  /**
   * get请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  get (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.get(this.getModulePathUrl(url), config)
  }

  /**
   * post请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  post (url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.post(this.getModulePathUrl(url), data, config)
  }

  /**
   * put请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  put (url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.put(this.getModulePathUrl(url), data, config)
  }

  /**
   * delete请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  delete (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.delete(this.getModulePathUrl(url), config)
  }

  /**
   * head请求
   * @param url{string}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  head (url: string, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.delete(this.getModulePathUrl(url), config)
  }

  /**
   * patch请求
   * @param url{string}
   * @param data{any}
   * @param config{AxiosRequestConfig}
   * @returns {Promise<AxiosResponse>}
   */
  patch (url: string, data: any, config?: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.nativeAxios.patch(this.getModulePathUrl(url), data, config)
  }

  /**
   * 解除重复请求锁定,可以多次请求,解除可能会出现数据展示错乱的情况
   * @param url{string}
   * @returns {ServerRequest}
   */
  unlock (url: string): ServerRequest {
    listenPendingAjax[this.getModulePathUrl(url)] = false
    return this
  }

  /**
   * 取消上一次请求,能保证数据是后面的请求返回的
   * @param url
   * @param params
   */
  cancel (url: string, params?: any): ServerRequest {
    if (params) {
      const urlSearch = url.replace(/#.*$/, '').split('?')[1]
      const urlHash = url.split('#')[1] ? '#' + url.split('#')[1] : ''
      urlSearch && Object.assign(params, qs.parse(urlSearch))
      url = url.split('?')[0] + '?' + qs.stringify(params) + urlHash
    }
    const resUrl = this.getModulePathUrl(url)
    if (listenPendingAjax[resUrl]) {
      listenPendingAjax[resUrl].cancel()
      listenPendingAjax[resUrl] = undefined
    }
    return this
  }
}

3.8 使用

import ServerRequest from '@/utils/request.ts'

const api = new ServerRequest('/api')

export interface login {
  userName: string,
  passWord: string
}

export default {
  /**
   * 登录
   */
  login: (data:login) => api.post('/login', data),
  /**
   * 测试
   */
  test:(data:{id:number,name:string}) => api.get('',{params: data})

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值