umijs-request小坑

300 阅读4分钟

前言

距离上一次遇到耗时半天解决bug写已经过去两个月了......

这次的场景是这样:正常的前后端交互是有固定的格式,来方便前端做统一拦截处理的,但是有一种例外的场景,那就是文件

这是最早的简单拦截器,也处理了下载,安全稳定用了2年,这次有个小伙伴有个需求需要预览,那我这个处理逻辑就没办法正确的拿到返回数据了。

// 响应拦截器
responseInterceptors: [
  (response: AxiosResponse) => {
    // 拦截响应数据,进行个性化处理
    const { data } = response as unknown as ResponseStructure;
    if (response.status !== 200) {
      return Promise.reject({ response: response }) as any;
    } else {
      if (data.code === '00000000') {
        return response.data;
      } else {
         if ((response.config as { isDownload: boolean })?.isDownload) {
           downloadBlob(response);
           return true;
         }
      }
      return Promise.reject({ response: response });
    }
  },
],

请求代码编写

export async function downloadFile(
  systemcode: string,
  bucketName: string,
  fileKey: string,
  view: boolean,
) {
  return request<string[]>('/api/file/download', {
    method: 'GET',
    params: { systemcode, bucketName, fileKey, view },
    isDownload: true,
  });
}

export async function preview(
  systemcode: string,
  bucketName: string,
  fileKey: string,
  view: boolean,
) {
  const response = await request('/api/file/download', {
    method: 'GET',
    params: { systemcode, bucketName, fileKey, view },
    isNoCode: true,
  });
  console.log(response);
  return response;
}

按照拦截器可以看出,代码会被拒绝然后抛出,也就是.catch可以获取到 (我:那你就在.catch里面写你的展示逻辑不就好了)

1 诡异的undefined

其实问题就是后端返回的格式数据结构,那就加一个isNocode来判断一下,返回就好了

// 拦截修改部分
if (response.status !== 200) {
  return Promise.reject({ response: response }) as any;
} else {
  if (data.code === '00000000') {
    return response.data;
  } else {
    if ((response.config as { isNoCode: boolean })?.isNoCode) {
      return response.data;
    }
    // return Promise.reject({ response: response });
  }
  return Promise.reject({ response: response });
}


// 请求代码
export async function preview(
  systemcode: string,
  bucketName: string,
  fileKey: string,
  view: boolean,
) {
  const response = await request('/api/file/download', {
    method: 'GET',
    params: { systemcode, bucketName, fileKey, view },
    isNoCode: true,
  });
  console.log(response);
  return response;
}

image.png

好好好,在线在新人面前翻车了,然后我说我一会看看-。-,结果调试了老半天

2 调试过程

2.1 怀疑上了Promise

一开始在想是不是因为return 的不是reaolve的问题,但是没去改,而是去看调试了平常的接口,不然直接破案了,我不可能去管为啥的,只要把上面代码的return response.data用Promise.resolve包裹就好了。

const requestParams = { ...params, systemCode, bucketPkId, dirKey };
const dd = await request<TableType.TableRequest<FileListTable>>('/api/file/list', {
  method: 'GET',
  params: isSortToParams(requestParams, sort),
});
console.log(dd);

居然dd有值,然后我就怀疑是不是umi或者axios对content-type为json的做了特殊处理 经过我各种调试后,giao没有一点头绪,为什么是undefined

2.2 直接改掉拦截器的返回

if (response.status !== 200) {
  return Promise.reject({ response: response }) as any;
} else {
  if (data.code === '00000000') {
    return response.data;
  } else {
    if ((response.config as { isNoCode: boolean })?.isNoCode) {
      return '123'
    }
  }
  return Promise.reject({ response: response });
}

还是undefined,直接当场裂开,然后就去翻axios的文档,发现没有介绍什么东西

2.3 意外破案

调试太多次了,调试过快,加冬天偏冷,手一抖点了按行执行,意外进了pulgin-request的文件 1737360856126.jpg

1737360876630.jpg

1737360915086.jpg

在这个步骤我也点了三遍,一直没有反应过来图3的三元表达式 getResponse为false,然后我看res有值没毛病,为啥到下一步代码就又为undefined了-。-

(所以经常就是去抽根烟回来突然就有了灵感,一直重复做一件事,思维会定式)

resolve(getResponse ? res : res.data);

我是一直到调试其它接口的时候发现了,返回的是res.data才是对的,才反应过来

3 总结与解决方式

3.1 结论

request这边有封装一层,取的是return里面的data,正好以前的代码返回格式

image.png

response.data里面还有data,起初的目标就是为了去掉最外层data不要每次都const data = res.data或者.then里面写if res.code==="0000000" 这种代码我想很多人都有见过,也是后面慢慢的开始用统一拦截

故而没有一点问题在之前和后端配合的情况

3.2 结论语方案

3.2.1 暂时没找到

而现在流返回直接没有了这个返回结果格式,根据上面的分析,传参只要有办法把getResponse变为true就行了

3.2.2 response

if (response.status !== 200) {
  return Promise.reject({ response: response }) as any;
} else {
  if (data.code === '00000000') {
    return response.data;
  } else {
    if ((response.config as { isNoCode: boolean })?.isNoCode) {
      return response
    }
  }
  return Promise.reject({ response: response });
}

3.3.3 最终修改

responseInterceptors: [
  (response: AxiosResponse) => {
    // blob类型另外处理
    if (
      response.headers?.['content-type'] &&
      !response.headers?.['content-type'].includes('application/json')
    ) {
      // 下载情况已特殊处理
      if ((response.config as { isDownload: boolean })?.isDownload) {
        downloadBlob(response);
        return true;
      } else {
        // 直接返回后端返回的数据
        return response;
      }
    }

    // 拦截响应数据,进行个性化处理
    const { data } = response as unknown as ResponseStructure;
    if (response.status !== 200) {
      return Promise.reject({ response: response }) as any;
    } else {
      if (data.code === '00000000') {
        return Promise.resolve(response.data);
      }
      return Promise.reject({ response: response });
    }
  },
],

因为后端可能还会返回图片,那总不能再单独处理,那就把json的当成正常和后端处理的情况,不是json的都是其它情况,数据丢出到交互那边自行处理