axios統一接口管理及優化


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

 

根據在項目的使用,發現有以下問題需要優化:

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

 

根據以上問題,采用了以下解決方案:

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

 

通過代碼展示一下(React項目):

service.ts

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;

 

在需要使用接口的地方:

import Service from "./service.ts"

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

 

說明:

  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中。這樣也符合我們語義化的目標。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM