錯(cuò)誤封裝axios配置,導(dǎo)致響應(yīng)出現(xiàn)疊加

業(yè)務(wù)需求

公司有多個(gè)項(xiàng)目共同用到了已封裝好的axios(funcation http()),基于去掉復(fù)制粘貼這種重復(fù)工作。

  • 統(tǒng)一封裝所有項(xiàng)目axios方法(\color{red}{本文問題重點(diǎn)}
  • 把封裝好的方法打包發(fā)布到公司npm私服(不涉及)
問題重現(xiàn)

Vue項(xiàng)目頁面Create(){}的時(shí)候調(diào)用了一個(gè)接口,相當(dāng)于調(diào)用了http()方法,此時(shí)響應(yīng)response還是正常的。
但是當(dāng)再調(diào)用任何接口的時(shí)候,response出現(xiàn)了多次(我在響應(yīng)攔截器中console了response,調(diào)用了幾次http(),就多出現(xiàn)幾次console)

// axios 封裝的方法(關(guān)鍵代碼)
// httpClient是axios重命名、因?yàn)槊總€(gè)項(xiàng)目的baseURL不一樣,所以每次需要傳一個(gè)base進(jìn)來、url是接口地址
export default function http(base, url, data = {}, type = "get", header = {}) {
  httpClient.defaults.baseURL = base;
  httpClient.interceptors.response.use(
    response => {
      console.log("response", response);
      return response
    },
    error => {
      console.log("error", error.response);
      if (error.response.status === 401 && error.response.data.code === 'nosso') {
        window.location.href = base + '/redirect/to/frontend?page=' + encodeURIComponent(window.location.href)
      }
      return error.response
    }
  );
  type = type.toLowerCase();
  let promise;
  return new Promise((resolve, reject) => {
    if (type === 'post') {
      promise = httpClient.post(url, data, {headers: header})
    } else if (type === 'put') {
      promise = httpClient.put(url, data, {headers: header})
    } else if (type === 'delete') {
      promise = httpClient.delete(url, {data: data, headers: header})
    } else {
      promise = httpClient.get(url, {params: data, headers: header})
    }
    promise.then(response => {
      resolve(response.data);
    }).catch(error => {
      reject(error)
    })
  })
}
Create后--正常情況
第一次調(diào)用退出方法--錯(cuò)誤情況
第二次調(diào)用退出方法--錯(cuò)誤情況

如果再點(diǎn)退出,response的數(shù)量會(huì)繼續(xù)累加。當(dāng)時(shí)看到這個(gè)情況后很不理解。首先能確定的是兩個(gè)請(qǐng)求格式和參數(shù)完全一致,那么問題只能在響應(yīng)和后端數(shù)據(jù)上了(排除后臺(tái)數(shù)據(jù)問題)。
百度了一圈,基本沒有發(fā)現(xiàn)這個(gè)問題的解決辦法(本來是沒有問題的,這個(gè)封裝的方法最后是由我自己改動(dòng)的。詳細(xì)改動(dòng):將baseURL和響應(yīng)攔截器放在了http()里面,就出現(xiàn)以上錯(cuò)誤。之所以會(huì)放在里面是因?yàn)閎ase位置問題,后面細(xì)說)。

為什么會(huì)出現(xiàn)這個(gè)問題 && 問題原因

項(xiàng)目以前http()的響應(yīng)攔截器里的地址是寫死的,封裝后,需要根據(jù)不同的項(xiàng)目給不同的請(qǐng)求前綴地址。而axios默認(rèn)的請(qǐng)求配置是在發(fā)生請(qǐng)求之前定義的。

原項(xiàng)目axios邏輯順序

如圖,調(diào)用http()的時(shí)候,需要將一個(gè)base傳入baseURL和響應(yīng)攔截器里面。因?yàn)槭桥渲庙?xiàng),有點(diǎn)違背代碼邏輯,所以將baseURL和響應(yīng)攔截器放在http()里面,如下圖:

有問題的axios邏輯順序

回到上面的問題,我猜測把響應(yīng)攔截器放在http()后,因?yàn)槊看味加袀€(gè)new Promise的過程,相當(dāng)于在項(xiàng)目里,每調(diào)一次http(),axios就多一個(gè)響應(yīng)攔截器配置,每個(gè)響應(yīng)都依次依賴,所以才導(dǎo)致調(diào)用一個(gè)接口,就多一個(gè)response結(jié)果。

解決

找到問題就好解決,最開始沒有想到,httpClient.default.baseURL可以當(dāng)做axios服務(wù)的全局變量。也就是說,我只需要把這個(gè)default.baseURL放在http()里面,響應(yīng)攔截器放在外面就可以了

httpClient.interceptors.response.use(
  response => {
    return response.data
  },
  error => {
    if (error.response.status === 401 && error.response.data.code === 'nosso') {
      window.location.href = httpClient.defaults.baseURL + '/redirect/to/frontend?page=' + encodeURIComponent(window.location.href)
    }
    return error.response
  }
);
/**
 * 封裝請(qǐng)求方法
 * @params(url)
 * @params(data)
 * returns { Promise }
 * @user NIGangJun <nigangjun@aeotrade.com>
 */
export default function http(base, url, data = {}, type = "get", header = {}) {
  httpClient.defaults.baseURL = base;
  type = type.toLowerCase();
  let promise;
  return new Promise((resolve, reject) => {
    if (type === 'post') {
      promise = httpClient.post(url, data, {headers: header})
    } else if (type === 'put') {
      promise = httpClient.put(url, data, {headers: header})
    } else if (type === 'delete') {
      promise = httpClient.delete(url, {data: data, headers: header})
    } else {
      promise = httpClient.get(url, {params: data, headers: header})
    }
    promise.then(response => {
      resolve(response);
    })
  })
}

就是把響應(yīng)攔截器放在外面,然后base替換成baseURL就行了。

有個(gè)優(yōu)化的地方:響應(yīng)攔截器resolve的數(shù)據(jù)換成了response.data,reject的數(shù)據(jù)換成了error.response。promise就直接去掉了catch(如果要catch,響應(yīng)攔截器中reject的數(shù)據(jù)要return Promise.reject(error.response),并且http()方法里不能再使用 new Promise封裝)

總結(jié)

雖然最后解決結(jié)果很簡單,但是中間這個(gè)過程不可忽略。

  • axios配置應(yīng)該符合規(guī)范;
  • 查找代碼問題應(yīng)該按照功能進(jìn)行拆分,依次查詢;

問題千變?nèi)f化,解決思路如出一轍——用心;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容