使用TS封装axios

记录一下用ts封装axios

一、type.d.ts

// type.ts
import type { AxiosRequestConfig } from 'axios'

export interface httpRequestConfig extends AxiosRequestConfig {
  baseURL?: string
  headers?: any
  timeout?: number
  apiType?: string
  json?: boolean
  form?: [boolean, string]
  formUpload?: [boolean, string]
}

// 定义通用响应结构
export interface ApiResponse<T> {
  code: number
  data: T
  message: string
}

二、http.ts 

// http.ts
import axios, {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError
} from 'axios'
import { httpRequestConfig, ApiResponse } from './types'
import { showToast } from 'vant'
import { API as configApi } from '@/conf/index'
import { userCommonStoreHook } from '@/stores/modules/common'
import * as qs from 'querystring'

// 获取接口根路径
const isProd = import.meta.env.MODE === 'production'
const BASE_PATH: any = isProd ? configApi.production : configApi.development

// 导出Request类,可以用来自定义传递配置来创建实例
export class Request {
  // private baseUrl: any = BASE_PATH
  // axios 实例
  public instance: AxiosInstance
  // 基础配置
  private baseConfig: httpRequestConfig = {
    // baseURL: this.baseUrl['DEFAULT'],
    headers: {
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json; charset=UTF-8'
    },
    timeout: 1000 * 60 // 设置超时时间
  }

  constructor(options: httpRequestConfig) {
    // 使用axios.create创建axios实例
    this.instance = axios.create(Object.assign(this.baseConfig, options))
    this.instance.interceptors.request.use(
      (options: httpRequestConfig) => {
        // 简化类型设置
        const headers = (options.headers = options.headers || {})

        if (options.form) {
          headers['Content-Type'] =
            'application/x-www-form-urlencoded; charset=UTF-8'
          delete options.form
        }
        if (options.formUpload) {
          headers['Content-Type'] = 'multipart/form-data; charset=UTF-8'
          delete options.formUpload
        }
        // 校验post数据格式
        const contentType = headers['Content-Type']
        if (
          typeof options.data === 'object' &&
          contentType &&
          String(contentType).indexOf('application/x-www-form-urlencoded') > -1
        ) {
          options.data = qs.stringify(options.data)
        }

        let url: any = options.url
        let ajaxPath = BASE_PATH[options.apiType || 'defaultAjaxPath']
        if (ajaxPath && !url.startsWith('http') && !url.startsWith('https')) {
          options.url = ajaxPath + url
        }
        return options
      },
      (error: AxiosError) => {
        // 请求错误,这里可以用全局提示框进行提示
        return Promise.reject(error)
      }
    )

    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        return response.data
      },
      (error: any) => {
        if (error.response) {
          const data = error.response.data
          const status = error.response.status
          let errMessage = data.message || '服务忙,请稍后重试(error)'
          switch (status) {
            case 400:
              errMessage = '请求错误(400)'
              break
            case 401:
              errMessage = '未授权,请重新登录(401)'
              // 这里可以做清空storage并跳转到登录页的操作
              break
            case 403:
              errMessage = '拒绝访问(403)'
              break
            case 404:
              errMessage = '404 Not Found'
              break
            case 408:
              errMessage = '请求超时(408)'
              break
            case 500:
              errMessage = '服务器错误(500)'
              break
            case 501:
              errMessage = '服务未实现(501)'
              break
            case 502:
              errMessage = '网络错误(502)'
              break
            case 503:
              errMessage = '服务不可用(503)'
              break
            case 504:
              errMessage = '网络超时(504)'
              break
            case 505:
              errMessage = 'HTTP版本不受支持(505)'
              break
            default:
              errMessage = `连接出错(${error.response.status})!`
          }
          showToast(`${errMessage},请检查网络或联系管理员!`)
        } else {
          // 默认放一个空对象避免其他地方报错
          error.response = {}
          console.error(
            (error.config && error.config.url) || '无url',
            '请求接口超过一分钟无响应'
          )
          const msg = userCommonStoreHook().networkState
            ? '您与服务器的连接已经断开,请联系管理员处理'
            : '网络连接已断开'
          showToast(msg)
        }
        return Promise.reject(error)
      }
    )
  }

  // 定义请求方法
  public request(config: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.instance.request(config)
  }

  public get<T = any>(
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    return this.instance.get(config?.url as string, config)
  }

  public post<T = any>(
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    return this.instance.post(config?.url as string, config?.data, config)
  }

  public put<T = any>(
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    return this.instance.put(config?.url as string, config?.data, config)
  }

  public delete<T = any>(
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    return this.instance.delete(config?.url as string, config)
  }
}

// 默认导出Request实例
export default new Request({})

三、conf/index.ts

/*
 * @Desc         : 环境配置信息
 * @Autor        : ZYH
 * @Date         : 2023-08-17 16:45:28
 * @LastEditors  : ZYH
 * @LastEditTime : 2023-08-17 16:47:58
 */

export const API = {
  // 开发环境
  development: {
    DEFAULT: import.meta.env.BASE_URL,
    defaultAjaxPath: '/webspiderweb'
  },
  // 生产环境
  production: {
    DEFAULT: import.meta.env.BASE_URL,
    defaultAjaxPath: '/webspiderweb'
  }
}

const isProd = import.meta.env.MODE === 'production'
export const BASE_CONFIG: AnyObject = isProd ? API.production : API.development
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值