随心而记
680 字
3 分钟
吐槽项目中下载接口的请求封装
2024-03-15
发布时间
分类
标签

前两天有个需求,页面中有个导出的按钮,需要导出报表,一开始后端给出的接口请求方式是 get 方式,但是考虑到未来可能请求的入参条件会非常多,可能会超过 url 长度最大值,所以将请求方式修改成了 post 请求。

但是将请求方式修改后发现,接口报了异常,查看原因是因为入参格式,在项目中发现这个项目将所有下载相关的接口的入参都改成了 formData 格式的,而后端并没有以此格式接收导致的。

处理下载请求配置方法如下:

const download = (requestUrl, method, instanceName, data) => {
  const formData = new FormData();
  if (data.bodyParams) {
    Object.keys(data.bodyParams).forEach((key) => {
      formData.append(key, data.bodyParams[key]);
    });
  } else {
    Object.keys(data).forEach((key) => {
      formData.append(key, data[key]);
    });
  }

  const req = {
    url: formatDownloadRequestV2(requestUrl, data),
    method: method.toUpperCase(),
    data: formData,
    headers: {
      'Content-Type': 'multipart/form-data',
      filename: 'utf-8',
    },
    responseType: 'blob',
    baseURL: config[`${instanceName ?? 'base'}URL`],
  };
};

在修改这个问题是又发现了另外一个可能存在的问题 就是 formatDownloadRequestV2 方法处理 url 时,如果是 get 请求并含有参数时,它会忽略它的参数,函数代码如下:

const formatDownloadRequestV2 = (requestUrl, data) => {
  // 组织请求参数
  let url = requestUrl;
  if (Object.prototype.hasOwnProperty.call(data, 'pathParams')) {
    Object.keys(data.pathParams).forEach((key) => {
      url = requestUrl.replace(`{${key}}`, data.pathParams[key]);
    });
  }
  if (Object.prototype.hasOwnProperty.call(data, 'urlParams')) {
    Object.keys(data.urlParams).forEach((key, index) => {
      url = index === 0 ? (url += `?${key}=${data.urlParams[key]}`) : (url += `&${key}=${data.urlParams[key]}`);
    });
  }
  if (Object.prototype.hasOwnProperty.call(data, 'bodyParams')) {
    return requestUrl;
  }
  return url;
};

总得来说有两处需要修改的

  1. 不将所有的请求的参数都修改为 formData 格式
  2. 修改 formatDownloadRequestV2 函数,使其正常处理 get 请求的 url

对于修改点 1 的修改如下:

我们项目中的接口定义通常如下:

  // 主播绩效-下载对比数据
  downloadCompareDate: {
    url: '/anchorPerformance/comparison/export',
    method: 'POST',
    instanceName: 'live',
    isDownload: true,
  },

首先在接口定义中加入 noFormData 配置参数

  // 主播绩效-下载对比数据
  downloadCompareDate: {
    noFormData: true,
  },

然后修改 download 方法

// 添加 形参 noFormData
const download = (requestUrl, method, instanceName, data, noFormData) => {
  const req = {
    url: formatDownloadRequestV2(requestUrl, data, method.toUpperCase()),
    method: method.toUpperCase(),
    // 如果不需要转成 formData 格式 则直接 将 data 传入
    data: noFormData ? data : formData,
    headers: {
      'Content-Type': noFormData ? 'application/json' : 'multipart/form-data',
      filename: 'utf-8',
    },
    responseType: 'blob',
    baseURL: config[`${instanceName ?? 'base'}URL`],
  };
};

对于修改点 2 的修改如下:

const formatDownloadRequestV2 = (requestUrl, data, method) => {
  // 组织请求参数
  let url = requestUrl;
  // 添加一个标识 判断是否走入下面三个 if 的逻辑中
  let flag = true;
  if (Object.prototype.hasOwnProperty.call(data, 'pathParams')) {
    flag = false;
    Object.keys(data.pathParams).forEach((key) => {
      url = requestUrl.replace(`{${key}}`, data.pathParams[key]);
    });
  }
  if (Object.prototype.hasOwnProperty.call(data, 'urlParams')) {
    flag = false;
    Object.keys(data.urlParams).forEach((key, index) => {
      url = index === 0 ? (url += `?${key}=${data.urlParams[key]}`) : (url += `&${key}=${data.urlParams[key]}`);
    });
  }
  if (Object.prototype.hasOwnProperty.call(data, 'bodyParams')) {
    flag = false;
    return requestUrl;
  }
  // 修改 get 请求的 url
  if (flag && method === 'GET') {
    url += formatURL(data);
  }
  return url;
};
吐槽项目中下载接口的请求封装
https://www.promises.top/posts/rants-on-wrapping-download-requests-in-projects/
作者
发布于
2024-03-15
许可协议
CC BY-NC-SA 4.0