溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ts如何封裝axios

發(fā)布時(shí)間:2023-03-13 11:15:34 來源:億速云 閱讀:294 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“ts如何封裝axios”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“ts如何封裝axios”吧!

什么樣封裝才是最合理的

別再用 promise 包了,好嗎?

看了一下,很多人封裝 axios 的時(shí)候都用 promise 包裝了一層,甚至更有甚者用起了 try catch。為什么反對(duì)用 promise 包裝,因?yàn)?axios 返回的就是個(gè) promise ,脫褲子放屁,完全沒必要????‍♀?。至于 try catch 這個(gè)是用于捕獲未知錯(cuò)誤的,比如 JSON.parse 的時(shí)候,有些字符串就是無法轉(zhuǎn)換。記住一句話,濫用 try catch 和隨地大小便沒有區(qū)別。

一個(gè) request 方法梭哈,噗!我一口老血????

部分人直接就一個(gè) request 方法梭哈,所有參數(shù)與配置都寫在一起,看起來一點(diǎn)也不清晰,簡(jiǎn)潔。請(qǐng)求有多種方式,get,postput...,最合理的請(qǐng)求方式應(yīng)該是 instance[method](url, data, options)。對(duì)應(yīng) 請(qǐng)求地址、請(qǐng)求參數(shù)、請(qǐng)求配置項(xiàng),一目了然。

擴(kuò)展我需要的請(qǐng)求,不要再 ts-ignore 了????

如果 ts-ignore 用多了,就會(huì)產(chǎn)生依賴性。不排除情況緊急急著上線,或者 類型處理 復(fù)雜的,但是在有時(shí)間的時(shí)候,還是得優(yōu)化一下,作為程序員,追求優(yōu)雅,永不過時(shí)。

求你了!把攔截器拿出來吧????

封裝的時(shí)候我們都會(huì)封裝一個(gè)請(qǐng)求類,但對(duì)應(yīng)攔截器應(yīng)該解耦出來。因?yàn)槊總€(gè)域名的攔截器處理可能不一致,寫死的話封裝請(qǐng)求類的意義也就沒有了。

接口請(qǐng)求 then 里面又判斷后端返回碼判斷請(qǐng)求是否成功,太狗血了!

看到下面這種代碼,給我難受的啊。

api.post(url, data).then((res) => {
  if (res.code === 1) {
    // ...
  } else {
    // 全局消息提示
    console.error(res.message)
  }
})

既然是一個(gè) promise ,我們就應(yīng)該知道 promise 只有成功或者失敗。then 怎么會(huì)有成功錯(cuò)誤的處理呢?then 里面就是請(qǐng)求成功,沒有什么 if else,處理失敗去 catch 里面處理去。這么喜歡寫 if else,你是沒寫過單元測(cè)試是吧?

開整

OK,吐槽了這么多,這時(shí)候肯定就有人說了,光說誰不會(huì)啊,你整一個(gè)?。????

瞧你這話說的,一點(diǎn)活沒干,還讓你白嫖了。你咋這么能呢?????

不過話說回來,我不要活在他人的評(píng)價(jià)里,我做這件事情不是因?yàn)槟愕闹S刺或者吹捧,而是我自己要做????‍????。

接下來定一下要做的事情

  • 封裝一個(gè)請(qǐng)求類

  • 適當(dāng)擴(kuò)展 axios 類型,為自定義配置打地基

  • 支持自定義請(qǐng)求配置。如是否全局錯(cuò)誤提示

  • 攔截器單獨(dú)拎出來,方便擴(kuò)展新的請(qǐng)求

開整之前先看看 axios 基本類型

// 這是 axios 請(qǐng)求類型定義,但是因?yàn)槲覀冃枰С肿远x配置,所以待會(huì)需要把它拓展一下
export interface AxiosRequestConfig<D = any> {
  url?: string;
  method?: Method | string;
  baseURL?: string;
  transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
  transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
  headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
  params?: any;
  paramsSerializer?: ParamsSerializerOptions;
  data?: D;
  timeout?: Milliseconds;
  timeoutErrorMessage?: string;
  withCredentials?: boolean;
  // ...
}
// 這是 axios 請(qǐng)求返回類型定義,里面類型需要處理,所以這個(gè)我們也得處理一下。
export interface AxiosResponse<T = any, D = any> {
  data: T;
  status: number;
  statusText: string;
  headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
  // 這里的配置沒有支持拓展,所以待會(huì)也得處理一下
  config: InternalAxiosRequestConfig<D>;
  request?: any;
}
// 所以我們只需要改造 3 個(gè) axios 類型定義就行了
// 另外我們需要定義下自己的攔截器 和 請(qǐng)求結(jié)果封裝

Talk is cheap,show me the code.

代碼也不多,就也不多解釋了,基本注釋都加上了。下面是全部代碼。

import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
// 定義一個(gè)常見后端請(qǐng)求返回
type BaseApiResponse<T> = {
  code: number
  message: string
  result: T
}
// 拓展 axios 請(qǐng)求配置,加入我們自己的配置
interface RequestOptions {
  // 是否全局展示請(qǐng)求 錯(cuò)誤信息
  globalErrorMessage?: boolean
  // 是否全局展示請(qǐng)求 成功信息
  globalSuccessMessage?: boolean
}
// 拓展自定義請(qǐng)求配置
interface ExpandAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
  interceptorHooks?: InterceptorHooks
  requestOptions?: RequestOptions
}
// 拓展 axios 請(qǐng)求配置
interface ExpandInternalAxiosRequestConfig<D = any> extends InternalAxiosRequestConfig<D> {
  interceptorHooks?: InterceptorHooks
  requestOptions?: RequestOptions
}
// 拓展 axios 返回配置
interface ExpandAxiosResponse<T = any, D = any> extends AxiosResponse<T, D> {
  config: ExpandInternalAxiosRequestConfig<D>
}
export interface InterceptorHooks {
  requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
  requestInterceptorCatch?: (error: any) => any
  responseInterceptor?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>
  responseInterceptorCatch?: (error: any) => any
}
// 導(dǎo)出Request類,可以用來自定義傳遞配置來創(chuàng)建實(shí)例
export default class Request {
  // axios 實(shí)例
  private _instance: AxiosInstance
  // 默認(rèn)配置
  private _defaultConfig: ExpandAxiosRequestConfig = {
    baseURL: '/api',
    timeout: 5000,
    requestOptions: {
      globalErrorMessage: true,
      globalSuccessMessage: false
    }
  }
  private _interceptorHooks?: InterceptorHooks
  constructor(config: ExpandAxiosRequestConfig) {
    // 使用axios.create創(chuàng)建axios實(shí)例
    this._instance = axios.create(Object.assign(this._defaultConfig, config))
    this._interceptorHooks = config.interceptorHooks
    this.setupInterceptors()
  }
  // 通用攔截,在初始化時(shí)就進(jìn)行注冊(cè)和運(yùn)行,對(duì)基礎(chǔ)屬性進(jìn)行處理
  private setupInterceptors() {
    this._instance.interceptors.request.use(this._interceptorHooks?.requestInterceptor, this._interceptorHooks?.requestInterceptorCatch)
    this._instance.interceptors.response.use(this._interceptorHooks?.responseInterceptor, this._interceptorHooks?.responseInterceptorCatch)
  }
  // 定義核心請(qǐng)求
  public request(config: ExpandAxiosRequestConfig): Promise<AxiosResponse> {
    // !??!?? 注意:axios 已經(jīng)將請(qǐng)求使用 promise 封裝過了
    // 這里直接返回,不需要我們?cè)偈褂?nbsp;promise 封裝一層
    return this._instance.request(config)
  }
  public get<T = any>(url: string, config?: ExpandAxiosRequestConfig): Promise<AxiosResponse<BaseApiResponse<T>>> {
    return this._instance.get(url, config)
  }
  public post<T = any>(url: string, data?: any, config?: ExpandAxiosRequestConfig): Promise<T> {
    return this._instance.post(url, data, config)
  }
  public put<T = any>(url: string, data?: any, config?: ExpandAxiosRequestConfig): Promise<T> {
    return this._instance.put(url, data, config)
  }
  public delete<T = any>(url: string, config?: ExpandAxiosRequestConfig): Promise<T> {
    return this._instance.delete(url, config)
  }
}

以及使用的 demo。這個(gè)保姆級(jí)服務(wù)滿意嗎?

// 請(qǐng)求攔截器
const transform: InterceptorHooks = {
  requestInterceptor(config) {
    // 請(qǐng)求頭部處理,如添加 token
    const token = 'token-value'
    if (token) {
      config!.headers!.Authorization = token
    }
    return config
  },
  requestInterceptorCatch(err) {
    // 請(qǐng)求錯(cuò)誤,這里可以用全局提示框進(jìn)行提示
    return Promise.reject(err)
  },
  responseInterceptor(result) {
    // 因?yàn)?nbsp;axios 返回不支持?jǐn)U展自定義配置,需要自己斷言一下
    const res = result as ExpandAxiosResponse
    // 與后端約定的請(qǐng)求成功碼
    const SUCCESS_CODE = 1
    if (res.status !== 200) return Promise.reject(res)
    if (res.data.code !== SUCCESS_CODE) {
      if (res.config.requestOptions?.globalErrorMessage) {
        // 這里全局提示錯(cuò)誤
        console.error(res.data.message)
      }
      return Promise.reject(res.data)
    }
    if (res.config.requestOptions?.globalSuccessMessage) {
      // 這里全局提示請(qǐng)求成功
      console.log(res.data.message)
    }
    // 請(qǐng)求返回值,建議將 返回值 進(jìn)行解構(gòu)
    return res.data.result
  },
  responseInterceptorCatch(err) {
    // 這里用來處理 http 常見錯(cuò)誤,進(jìn)行全局提示
    const mapErrorStatus = new Map([
      [400, '請(qǐng)求方式錯(cuò)誤'],
      [401, '請(qǐng)重新登錄'],
      [403, '拒絕訪問'],
      [404, '請(qǐng)求地址有誤'],
      [500, '服務(wù)器出錯(cuò)']
    ])
    const message = mapErrorStatus.get(err.response.status) || '請(qǐng)求出錯(cuò),請(qǐng)稍后再試'
    // 此處全局報(bào)錯(cuò)
    console.error(message)
    return Promise.reject(err.response)
  }
}
// 具體使用時(shí)先實(shí)例一個(gè)請(qǐng)求對(duì)象
const request = new Request({
  baseURL: '/api',
  timeout: 5000,
  interceptorHooks: transform
})
// 定義請(qǐng)求返回
interface ResModel {
  str: string
  num: number
}
// 發(fā)起請(qǐng)求
request
  .post<ResModel>(
    '/abc',
    {
      a: 'aa',
      b: 'bb'
    },
    {
      requestOptions: {
        globalErrorMessage: true
      }
    }
  )
  .then((res) => {
    console.log('res: ', res)
    console.log(res.str)
  })

可以看到鼠標(biāo)浮上去就能看到定義了,完美!

ts如何封裝axios

到此,相信大家對(duì)“ts如何封裝axios”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI