美文网首页
错误封装axios配置,导致响应出现叠加

错误封装axios配置,导致响应出现叠加

作者: NIGangJun | 来源:发表于2019-07-16 18:32 被阅读0次
业务需求

公司有多个项目共同用到了已封装好的axios(funcation http()),基于去掉复制粘贴这种重复工作。

  • 统一封装所有项目axios方法(\color{red}{本文问题重点}
  • 把封装好的方法打包发布到公司npm私服(不涉及)
问题重现

Vue项目页面Create(){}的时候调用了一个接口,相当于调用了http()方法,此时响应response还是正常的。
但是当再调用任何接口的时候,response出现了多次(我在响应拦截器中console了response,调用了几次http(),就多出现几次console)

// axios 封装的方法(关键代码)
// httpClient是axios重命名、因为每个项目的baseURL不一样,所以每次需要传一个base进来、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后--正常情况 第一次调用退出方法--错误情况 第二次调用退出方法--错误情况

如果再点退出,response的数量会继续累加。当时看到这个情况后很不理解。首先能确定的是两个请求格式和参数完全一致,那么问题只能在响应和后端数据上了(排除后台数据问题)。
百度了一圈,基本没有发现这个问题的解决办法(本来是没有问题的,这个封装的方法最后是由我自己改动的。详细改动:将baseURL和响应拦截器放在了http()里面,就出现以上错误。之所以会放在里面是因为base位置问题,后面细说)。

为什么会出现这个问题 && 问题原因

项目以前http()的响应拦截器里的地址是写死的,封装后,需要根据不同的项目给不同的请求前缀地址。而axios默认的请求配置是在发生请求之前定义的。

原项目axios逻辑顺序

如图,调用http()的时候,需要将一个base传入baseURL和响应拦截器里面。因为是配置项,有点违背代码逻辑,所以将baseURL和响应拦截器放在http()里面,如下图:

有问题的axios逻辑顺序

回到上面的问题,我猜测把响应拦截器放在http()后,因为每次都有个new Promise的过程,相当于在项目里,每调一次http(),axios就多一个响应拦截器配置,每个响应都依次依赖,所以才导致调用一个接口,就多一个response结果。

解决

找到问题就好解决,最开始没有想到,httpClient.default.baseURL可以当做axios服务的全局变量。也就是说,我只需要把这个default.baseURL放在http()里面,响应拦截器放在外面就可以了

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
  }
);
/**
 * 封装请求方法
 * @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);
    })
  })
}

就是把响应拦截器放在外面,然后base替换成baseURL就行了。

有个优化的地方:响应拦截器resolve的数据换成了response.data,reject的数据换成了error.response。promise就直接去掉了catch(如果要catch,响应拦截器中reject的数据要return Promise.reject(error.response),并且http()方法里不能再使用 new Promise封装)

总结

虽然最后解决结果很简单,但是中间这个过程不可忽略。

  • axios配置应该符合规范;
  • 查找代码问题应该按照功能进行拆分,依次查询;

问题千变万化,解决思路如出一辙——用心;

相关文章

网友评论

      本文标题:错误封装axios配置,导致响应出现叠加

      本文链接:https://www.haomeiwen.com/subject/eztfkctx.html