java中post请求调用下载文件接口浏览器未弹窗而是返回一堆json,为啥

简介: 客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗;> 正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。

1.jpeg

1.背景描述

客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗;
正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。

image.png

image.png

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",
        ...

image.png

如图1

问题:为啥会报如图1中的错误?

答案:
image.png

最终方案:不采用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);
            }
        }
    }
目录
相关文章
|
5天前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
3天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
4天前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
16 4
|
7天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
7天前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
|
16天前
|
Java Apache Maven
Java将word文档转换成pdf文件的方法?
【10月更文挑战第13天】Java将word文档转换成pdf文件的方法?
49 1
|
16天前
|
监控 Java
Java定时扫码一个文件夹下的文件,如何保证文件写入完成后才进行处理?
【10月更文挑战第13天】Java定时扫码一个文件夹下的文件,如何保证文件写入完成后才进行处理?
59 1
|
9天前
|
缓存 Java 程序员
Java|SpringBoot 项目开发时,让 FreeMarker 文件编辑后自动更新
在开发过程中,FreeMarker 文件编辑后,每次都需要重启应用才能看到效果,效率非常低下。通过一些配置后,可以让它们免重启自动更新。
16 0
|
12天前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
1天前
|
JSON 缓存 前端开发
PHP如何高效地处理JSON数据:从编码到解码
在现代Web开发中,JSON已成为数据交换的标准格式。本文探讨了PHP如何高效处理JSON数据,包括编码和解码的过程。通过简化数据结构、使用优化选项、缓存机制及合理设置解码参数等方法,可以显著提升JSON处理的性能,确保系统快速稳定运行。