axios統一接口管理及優化

以前我寫了一篇文章,分享了本身的項目中對於接口管理的方法。總結下來就是:定義接口文件--withAxios導出--調用接口方法。這樣實現了接口的統一管理和調用接口的語義化與簡單化。html

 

根據在項目的使用,發現有如下問題須要優化:ios

  1. withAxios導出的接口方法對象對編輯器來講是不透明的,因此代碼提示功能缺失。
  2. 同一個方法調用屢次,如何保證組件老是獲取到最後一次的返回信息。

 

根據以上問題,採用瞭如下解決方案:typescript

  1. 使用typescript的泛型解決。
  2. 調用同一個方法時,取消掉上次未完成的請求,這裏使用axios的cancel方法。實現思路是在返回的方法對象中增長一個`${name}Cancel`的方法,保存取消上一次方法的回調,下次請求時固定調用這個取消方法以保證本次請求是當前惟一一個請求。(這裏只提供axios層面的解決辦法,不討論其餘辦法,好比採用redux-saga的話可使用takeLatest解決)

 

經過代碼展現一下(React項目):redux

service.tsaxios

import { IApiItem } from '@/configs/api/declares';
import withAxios from '@/utils/withAxios';

const api: IApiItem[] = [
  { name: 'getSummary', url: 'http://xx:8000/api/getSummary' },
  { name: 'getDetail', url: 'http://xx:8000/api/getDetail' },
  { name: 'getDetailChildren', url: 'http://xx:8000/api/getDetailChildren' },
  { name: 'getCurrentUser', url: 'http://xx:8000/api/getCurrentUser' },
];

interface IProdMonitorApi {
  getSummary: any;
  getDetail: any;
  getDetailChildren: any;
  getCurrentUser: any;
}

export default withAxios<IProdMonitorApi>(api);

 

withAxios.ts後端

function withAxios<T>(apiConfig: IApiItem[], usePassportOrigin: boolean = false): T {
  const serviceMap = {} as T;
  apiConfig.map(({ name, url, method = 'get', ...rest }: IApiItem) => {
    return (serviceMap[name] = async function(data = {}) {
      if (serviceMap[`${name}Cancel`] && typeof serviceMap[`${name}Cancel`] === 'function') {
        serviceMap[`${name}Cancel`]();
      }

      const source = axios.CancelToken.source();
      serviceMap[`${name}Cancel`] = () => {
        source.cancel(`已取消上次未完成請求:${name}`);
      };
      rest.cancelToken = source.token;

      let key = 'params';
      const apiMethod = method.toLowerCase();
      if (apiMethod === 'post' || apiMethod === 'put') {
        key = 'data';
      }
      let fetchUrl = url;
      if (url.indexOf('http') !== 0) {
        fetchUrl = usePassportOrigin
          ? NetworkUtils.passportOrigin + url
          : NetworkUtils.serverOrigin + url;
      }
      return axios({
        method,
        url: fetchUrl,
        [key]: data,
        fetchName: name,
        ...rest,
      } as AxiosRequestConfig);
    });
  });
  return serviceMap;
}

export default withAxios;

 

在須要使用接口的地方:api

import Service from "./service.ts"

Service.getSummary(requestParams).then(...)

 

說明:async

  1. 使用泛型雖然有了代碼提示,可是額外增長了編碼量,由於要手動維護一個方法接口,有利有弊吧,經過ts我尚未找到更好的方法。同事以前有過一個解決辦法:接口管理使用對象的形式,而後withAxios修改這個對象各屬性的getter,將getter指向經過axios包裝後的方法,最終實現了本文相同的調用方式和代碼提示,但這種方法有點hack的感受。
  2. cancel掉上一個接口這種方式保證了數據老是來源於最後一個請求接口,但有時可能會出現問題,好比:在同一個頁面須要展現兩種用戶:common用戶和admin用戶,後端給的接口是/api/v1/user,當參數type=1時爲common,type=2時爲admin,若是咱們把這個接口定義爲一個方法getUser,在這個頁面會同時發出兩個請求:Service.getUser({type:1}),Service.getUser({type:2}),可是,因爲withAxios會取消上一個相同方法的請求,那麼極可能有一個請求被取消,解決辦法是在service中定義爲兩種方法:getCommonUser和getAdminUser,將type直接寫入url中。這樣也符合咱們語義化的目標。
相關文章
相關標籤/搜索