基于axios的HttpClient请求封装

项目使用代码 个人封装 可直接复制粘贴使用。
项目是基于react的 需结合自己项目使用框架进行适当修改。

import { message as Message } from 'antd'
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'

export const PRD_URL_PREFIX_ACTIVITY = '/api/activity/'
export const PRD_URL_PREFIX_BASE = '/api'

export type IErrorHandler = (statusCode: number, message: string) => void
const defaultErrorHandler: IErrorHandler = (statusCode, message) => {
  Message.error(typeof message === 'string' ? message : JSON.stringify(message))
}

export interface IRequestConfig extends AxiosRequestConfig {
  // 是否阻止提示错误消息
  suppressErrorMessage?: boolean
}
export interface IResponse {
  status: string
  data: T
  message?: string
}
export interface IResponse2 {
  code: string | number
  data: T
  message: string
}

export class HttpClient {
  // 是否为生产环境
  private isProduction: boolean = false

  constructor(isProduction: boolean, errorHandler?: IErrorHandler) {
    this.isProduction = Boolean(isProduction)
    if (errorHandler) {
      this.errorHandler = errorHandler
    }
  }

  // 错误处理函数
  public errorHandler: IErrorHandler = (statusCode: number, message: string) => {
    console.error(message)
  }

  /**
   * 为发布环境处理URL
   */
  public dealUrlForPrd(url: string) {
    return this.isProduction ? url.replace(/^\/?api/g, '/marketApi') : url
  }

  /**
   * 转义查询参数
   */
  public encode(queryString?: string | null): string {
    if (!queryString) {
      return ''
    }

    return encodeURIComponent(queryString.replace(/[-[\]{}()*+?.,\\/^$|#]/g, '\\$&'))
  }

  /**
   * get查询
   */
  public async get(url: string, requestConfig: IRequestConfig = {}) {
    const { suppressErrorMessage, ...config } = requestConfig

    try {
      const response: AxiosResponse = await axios({
        url: this.getUrlWithTimestamp(this.dealUrlForPrd(url)),
        method: 'GET',
        headers: {
          'content-type': 'application/json; charse=UTF-8',
        },
        ...config,
      })
      return this.handleSuccess(response, suppressErrorMessage)
    } catch (e) {
      this.handleError(e, suppressErrorMessage)
      throw e
    }
  }

  /**
   * post查询
   */
  public async post(
    url: string,
    obj?: object | string,
    requestConfig: IRequestConfig = {}
  ): Promise {
    const { suppressErrorMessage, ...config } = requestConfig

    let data = {}
    if (typeof obj === 'string') {
      try {
        data = JSON.parse(obj)
      } catch (e) {
        throw new Error(`请求参数解析失败\n${obj}\n${url}\n${e}`)
      }
    } else if (typeof obj === 'object') {
      data = obj
    }

    try {
      const response: AxiosResponse = await axios({
        url: this.dealUrlForPrd(url),
        method: 'POST',
        headers: {
          'content-type': 'application/json; charse=UTF-8',
        },
        data,
        ...config,
      })
      return this.handleSuccess(response, suppressErrorMessage)
    } catch (e) {
      this.handleError(e, suppressErrorMessage)
      throw e
    }
  }

  /**
   * del请求
   */
  public async del(url: string, requestConfig: IRequestConfig = {}): Promise {
    const { suppressErrorMessage, ...config } = requestConfig

    try {
      const response: AxiosResponse = await axios({
        url: this.getUrlWithTimestamp(this.dealUrlForPrd(url)),
        method: 'DELETE',
        headers: {
          'content-type': 'application/json; charse=UTF-8',
        },
        ...config,
      })
      return this.handleSuccess(response, suppressErrorMessage)
    } catch (e) {
      this.handleError(e, suppressErrorMessage)
      throw e
    }
  }

  /**
   * 上传文件
   */
  public async uploadFile(
    url: string,
    file: File,
    requestConfig: IRequestConfig = {}
  ): Promise {
    const { suppressErrorMessage, ...config } = requestConfig
    const formData = new FormData()

    try {
      formData.append('file', file)
      const response: AxiosResponse = await axios.post(url, formData, {
        headers: {
          'content-type': 'multipart/form-data',
        },
        ...config,
      })
      return this.handleSuccess(response, suppressErrorMessage)
    } catch (e) {
      this.handleError(e, suppressErrorMessage)
      throw e
    }
  }

  /**
   * 处理请求成功
   */
  private handleSuccess(response: AxiosResponse, suppressErrorMessage: boolean = false): T {
    let message: string | undefined
    switch (response.status) {
      case 200:
        break

      case 400:
        message = '请求参数错误!'
        break

      case 401:
        message = '认证失败!'
        break

      case 403:
        message = '没有访问权限!'
        break

      case 415:
        message = '请求方式错误!'
        break

      default:
        message = '未知状态错误!'
        break
    }

    if (message && !suppressErrorMessage) {
      this.errorHandler(response.status, message)
    }

    // tslint:disable-next-line: no-object-literal-type-assertion
    return response.data || ({} as T)
  }

  /**
   * 处理请求失败
   */
  private handleError(error: AxiosError, suppressErrorMessage: boolean = false): void {
    let status: number = 0
    let message: string = '请求出错'

    /* 构造错误消息 */
    if (error.response) {
      status = error.response.status
      if (error.response.data.message) {
        message = error.response.data.message
      } else if (error.response.data.error) {
        message = error.response.data.error
      } else if (error.response.data.detail) {
        message = error.response.data.detail
      } else {
        if (status === 404) {
          message = error.message
        } else {
          message = error.response.data
        }
      }
    } else if (error.request) {
      status = error.request.status
      message = error.request.responseText
    } else {
      message = error.message
    }

    if (!suppressErrorMessage) {
      this.errorHandler(status, message)
    }
  }

  /**
   * 构造请求地址,添加时间戳参数,在开发环境禁用缓存
   * @param url 请求地址
   */
  private getUrlWithTimestamp(url: string): string {
    return this.isProduction
      ? url
      : `${url}${url.indexOf('?') > -1 ? '&' : '?'}_=${new Date().getTime()}`
  }
}

export default new HttpClient(process.env.REACT_APP_ENV!.trim() === 'prd', defaultErrorHandler)

你可能感兴趣的:(基于axios的HttpClient请求封装)