680 字
3 分钟
吐槽项目中下载接口的请求封装
前两天有个需求,页面中有个导出的按钮,需要导出报表,一开始后端给出的接口请求方式是 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;
};
总得来说有两处需要修改的
- 不将所有的请求的参数都修改为 formData 格式
- 修改 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;
};