java 中 post 请求调用下载文件接口浏览器未弹窗而是返回一堆 json,为啥
作者:刘大猫
- 2025-08-21 黑龙江
本文字数:4658 字
阅读完需:约 15 分钟
@[toc]
1.背景描述
客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器 F12 查看居然返回一堆 json,而没有另存为弹窗;正确的效果应该是:接口调用成功且浏览器 F12 不返回任何 json,而是弹窗另存为窗口,直接保存文件即可。
2.项目代码
代码说明:具体的引入或者工具类啥的就不复制粘贴了,就是你可以理解为给你个硬盘地址,然后封装成 File,以流输出,或者以 poi 依赖包的 WorkBook 输出流都可以。
前端 js 代码
//批量管理-下载批量导入数据function downloadBatchImportDataTaskActionColumn(taskId) { var param = { taskId: taskId } $.ajax({ async: true, url: prefix + "/downloadBatchImportData", type: 'post', data: JSON.stringify(param), dataType: 'json', contentType: "application/json;charset=UTF-8", beforeSend:function(){ window.parent.showLoading(); }, success: function (res) { window.parent.completeLoading(); console.log(res);
}, error:function(){ window.parent.completeLoading(); } });}
复制代码
后端代码
/** * 下载批量导入数据 * @param req req * @param response response */ @RequestMapping(value = "/downloadBatchImportData") public void downloadBatchImportData(HttpServletRequest req, @RequestBody QueryTaskRes queryTaskRes, HttpServletResponse response) {// String taskId = req.getParameter("taskId");// logger.info("-downloadBatchImportData-taskId:{}", taskId); OutputStream os = null; InputStream io = null; String tempFilePath = TEMP_FILE_PATH; String fileName = "";
try { ImpExpTaskDetail impExpTaskDetail = isvcBatchTaskServiceMicro.selectTaskDetailByTaskId(queryTaskRes.getTaskId()); String filedownLink = impExpTaskDetail.getLink(); if (org.springframework.util.StringUtils.isEmpty(filedownLink)) { fileName = MessageUtils.message("batch.download") + ".xlsx"; } else { fileName = StringUtils.subscribeNameString(filedownLink); } logger.info("-tempFilePath:{},fileName:{}", tempFilePath, fileName);
File file = ResourceUtils.getFile(String.join(File.separator, tempFilePath, fileName)); if (!file.exists()) { String begin = DateUtil.now(); DateTime beginTime = DateUtil.parse(begin); long download = HttpUtil.downloadFile(filedownLink, FileUtil.file(tempFilePath, fileName), new StreamProgress() { @Override public void start() { logger.info("开始下载,时间为:" + begin); }
@Override public void progress(long progressSize) { logger.info("已下载:{}", FileUtil.readableFileSize(progressSize)); }
@Override public void finish() { String end = DateUtil.now(); DateTime endTime = DateUtil.parse(end); long between = DateUtil.between(beginTime, endTime, DateUnit.MS); logger.info("下载完成,用时:" + DateUtil.formatBetween(between, BetweenFormatter.Level.SECOND)); } }); }
io = new FileInputStream(file); Workbook wb = new XSSFWorkbook(io); response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); wb.write(response.getOutputStream()); } catch (IOException e) { logger.error("-downloadBatchImportData error:{}", e.getMessage()); } finally { if (os != null) { try { os.close(); } catch (IOException e) { logger.error("-OutputStream error:{}", e.getMessage()); } } if (io != null) { try { io.close(); } catch (IOException e) { logger.error("-InputStream error:{}", e.getMessage()); } } if (Optional.ofNullable(tempFilePath).isPresent()) { // 强制删除临时文件 boolean isDelete = com.hytalk.util.FileUtil.delFile(new File(tempFilePath)); logger.info("-downloadBatchImportData 强制删除临时文件 , filePath: {} , isDelete : {} ", tempFilePath, isDelete); } } }
复制代码
3.导致错误原因分析
最终的错误原因就是: 因为使用了 ajax 发请求,请看下方代码,这里面的 dataType 和 contentType 用来设置传参类型及返回类型,只要设置这两个返回的就是 json 字符串,而不会以文件流输出。但是如果不写这两 dataType+contentType 值,那么 contentType 的默认值为 application/x-www-form-urlencoded,最终效果也不行而且会报错。报错如图 1。
$.ajax({ async: true, url: prefix + "/downloadBatchImportData", type: 'post', data: JSON.stringify(param), dataType: 'json', contentType: "application/json;charset=UTF-8", ...
复制代码
<center><font color='red'>如图 1</font></center>
问题:为啥会报如图 1 中的错误?
答案:
最终方案:不采用 ajax 发送请求,而是采用最普遍的 form 表单的方式提交就可以实现效果。
前端 js 代码
//批量管理-下载批量导入数据function downloadBatchImportDataTaskActionColumn(taskId) { var url = prefix + "/downloadBatchImportData"; var form = $("<form></form>").attr("action", url).attr("method", "post"); form.append($("<input></input>").attr("type", "hidden").attr("name", "taskId").attr("value", taskId)); form.appendTo('body').submit().remove();}
复制代码
后端代码
/** * 下载批量导入数据 * @param req req * @param response response */ @RequestMapping(value = "/downloadBatchImportData") public void downloadBatchImportData(HttpServletRequest req, HttpServletResponse response) { String taskId = req.getParameter("taskId"); logger.info("-downloadBatchImportData-taskId:{}", taskId); OutputStream os = null; InputStream io = null; String tempFilePath = TEMP_FILE_PATH; String fileName = "";
try { ImpExpTaskDetail impExpTaskDetail = isvcBatchTaskServiceMicro.selectTaskDetailByTaskId(taskId); String filedownLink = impExpTaskDetail.getLink(); if (org.springframework.util.StringUtils.isEmpty(filedownLink)) { fileName = MessageUtils.message("batch.download") + ".xlsx"; } else { fileName = StringUtils.subscribeNameString(filedownLink); } logger.info("-tempFilePath:{},fileName:{}", tempFilePath, fileName);
File file = ResourceUtils.getFile(String.join(File.separator, tempFilePath, fileName)); if (!file.exists()) { String begin = DateUtil.now(); DateTime beginTime = DateUtil.parse(begin); long download = HttpUtil.downloadFile(filedownLink, FileUtil.file(tempFilePath, fileName), new StreamProgress() { @Override public void start() { logger.info("开始下载,时间为:" + begin); }
@Override public void progress(long progressSize) { logger.info("已下载:{}", FileUtil.readableFileSize(progressSize)); }
@Override public void finish() { String end = DateUtil.now(); DateTime endTime = DateUtil.parse(end); long between = DateUtil.between(beginTime, endTime, DateUnit.MS); logger.info("下载完成,用时:" + DateUtil.formatBetween(between, BetweenFormatter.Level.SECOND)); } }); }
io = new FileInputStream(file); Workbook wb = new XSSFWorkbook(io); response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); wb.write(response.getOutputStream()); } catch (IOException e) { logger.error("-downloadBatchImportData error:{}", e.getMessage()); } finally { if (os != null) { try { os.close(); } catch (IOException e) { logger.error("-OutputStream error:{}", e.getMessage()); } } if (io != null) { try { io.close(); } catch (IOException e) { logger.error("-InputStream error:{}", e.getMessage()); } } if (Optional.ofNullable(tempFilePath).isPresent()) { // 强制删除临时文件 boolean isDelete = com.hytalk.util.FileUtil.delFile(new File(tempFilePath)); logger.info("-downloadBatchImportData 强制删除临时文件 , filePath: {} , isDelete : {} ", tempFilePath, isDelete); } } }
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 4
刘大猫
关注
还未添加个人签名 2022-08-23 加入
还未添加个人简介









评论