前端文件下载实战:从原理到最佳实践
引言
在现代 Web 应用开发中,文件下载是一个常见但容易出错的场景。本文将通过一个真实的订单导出功能案例,详细介绍前后端协作实现文件下载的完整方案,分析常见问题及解决方案,并提供经过生产验证的最佳实践。
一、需求背景与初始实现
1.1 业务需求
我们需要实现一个订单数据导出功能,允许用户将查询结果下载为 Excel 文件。具体要求包括:
- 支持按任务 ID 筛选订单
- 生成规范的 XLSX 格式文件
- 显示友好的下载状态
- 记录操作日志
1.2 初始后端实现
@ApiOperation(value = "下载订单列表", notes = "根据条件导出订单数据为 Excel 文件")
@PostMapping("/order-list/download")
public Result<?> downloadTaskOrderExcel(@RequestBody TaskDownLoadRequest taskDownLoadRequest, HttpServletRequest httpRequest) {
try {
// 获取用户 ID 并记录日志
Integer userId = getUserId(taskDownLoadRequest.getTaskId());
logDownloadStart(userId, taskDownLoadRequest.getTaskId());
// 查询订单数据
List<CustomerOrder> orders = queryOrders(taskDownLoadRequest.getTaskId());
if (orders.isEmpty()) {
return Result.error("没有找到符合条件的订单数据");
}
// 生成 Excel 文件
ByteArrayResource resource = generateExcel(orders);
// 构建响应数据
Map<String, Object> data = buildResponseData(resource);
return Result.ok(data);
} catch (Exception e) {
log.error("下载订单列表失败", e);
return Result.error(500, "下载订单数据失败");
}
}
1.3 初始前端实现
const download = async () => {
loading = .({ : });
{
response = commonApi.(
{ : row. },
{ : }
);
filename = ;
disposition = response.[];
(disposition) {
match = disposition.();
(match) filename = (match[]);
}
blob = ([response.], {
:
});
link = .();
link. = ..(blob);
link. = filename;
..(link);
link.();
..(link);
.();
} (e) {
.();
} {
loading.();
}
};


