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);
            }
        }
    }
目录
相关文章
|
9月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
605 6
|
9月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
331 1
|
12月前
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
484 14
|
存储 Java 数据安全/隐私保护
Java技术栈揭秘:Base64加密和解密文件的实战案例
以上就是我们今天关于Java实现Base64编码和解码的实战案例介绍。希望能对你有所帮助。还有更多知识等待你去探索和学习,让我们一同努力,继续前行!
703 5
|
12月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
338 0
|
12月前
|
存储 人工智能 Java
java之通过Http下载文件
本文介绍了使用Java实现通过文件链接下载文件到本地的方法,主要涉及URL、HttpURLConnection及输入输出流的操作。
781 0
|
10月前
|
机器学习/深度学习 JSON 监控
淘宝拍立淘按图搜索与商品详情API的JSON数据返回详解
通过调用taobao.item.get接口,获取商品标题、价格、销量、SKU、图片、属性、促销信息等全量数据。
|
9月前
|
JSON API 数据格式
淘宝拍立淘按图搜索API系列,json数据返回
淘宝拍立淘按图搜索API系列通过图像识别技术实现商品搜索功能,调用后返回的JSON数据包含商品标题、图片链接、价格、销量、相似度评分等核心字段,支持分页和详细商品信息展示。以下是该API接口返回的JSON数据示例及详细解析:
|
9月前
|
JSON 算法 API
Python采集淘宝商品评论API接口及JSON数据返回全程指南
Python采集淘宝商品评论API接口及JSON数据返回全程指南
|
9月前
|
JSON API 数据安全/隐私保护
Python采集淘宝拍立淘按图搜索API接口及JSON数据返回全流程指南
通过以上流程,可实现淘宝拍立淘按图搜索的完整调用链路,并获取结构化的JSON商品数据,支撑电商比价、智能推荐等业务场景。