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);
            }
        }
    }
目录
相关文章
|
XML JSON API
淘宝商品详情API的调用流程(python请求示例以及json数据示例返回参考)
JSON数据示例:需要提供一个结构化的示例,展示商品详情可能包含的字段,如商品标题、价格、库存、描述、图片链接、卖家信息等。考虑到稳定性,示例应基于淘宝开放平台的标准响应格式。
|
XML JSON API
如何在 Postman 中上传文件和 JSON 数据
如果你想在 Postman 中同时上传文件和 JSON 数据,本文将带你一步一步地了解整个过程,包括最佳实践和技巧,让你的工作更轻松。
|
JSON Java 数据格式
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
492 25
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
|
开发工具 git 索引
怎么取消对project.private.config.json这个文件的git记录
通过以上步骤,您可以成功取消对 `project.private.config.json`文件的Git记录。这样,文件将不会被包含在未来的提交中,同时仍保留在您的工作区中。
483 28
|
运维 Cloud Native Java
postman发起post请求遇到报错:java.io.FileNotFoundException (文件名、目录名或卷标语法不正确。)
遇到bug报错,多猜可能的原因,控制变量反复测试,直至找到问题的关键,然后再思考如何解决或者回避。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来
|
JSON 数据格式 Python
Python实用记录(十四):python统计某个单词在TXT/JSON文件中出现的次数
这篇文章介绍了一个Python脚本,用于统计TXT或JSON文件中特定单词的出现次数。它包含两个函数,分别处理文本和JSON文件,并通过命令行参数接收文件路径、目标单词和文件格式。文章还提供了代码逻辑的解释和示例用法。
723 0
Python实用记录(十四):python统计某个单词在TXT/JSON文件中出现的次数
|
JSON 数据格式 计算机视觉
Opencv实用笔记(一): 获取并绘制JSON标注文件目标区域(可单独保存目标小图)
本文介绍了如何使用OpenCV和Python根据JSON标注文件获取并绘制目标区域,同时可将裁剪的图像单独保存。通过示例代码,展示了如何读取图片路径、解析JSON标注、绘制标注框并保存裁剪图像的过程。此外,还提供了相关的博客链接,供读者进一步学习。
691 0
|
算法 开发者
Moment.js库是如何处理不同浏览器的时间戳格式差异的?
总的来说,Moment.js 通过一系列的技术手段和策略,有效地处理了不同浏览器的时间戳格式差异,为开发者提供了一个稳定、可靠且易于使用的时间处理工具。
1048 156
|
JavaScript 前端开发 数据处理
模板字符串和普通字符串在浏览器和 Node.js 中的性能表现是否一致?
综上所述,模板字符串和普通字符串在浏览器和 Node.js 中的性能表现既有相似之处,也有不同之处。在实际应用中,需要根据具体的场景和性能需求来选择使用哪种字符串处理方式,以达到最佳的性能和开发效率。
545 63
|
JSON 移动开发 JavaScript
在浏览器执行js脚本的两种方式
【10月更文挑战第20天】本文介绍了在浏览器中执行HTTP请求的两种方式:`fetch`和`XMLHttpRequest`。`fetch`支持GET和POST请求,返回Promise对象,可以方便地处理异步操作。`XMLHttpRequest`则通过回调函数处理请求结果,适用于需要兼容旧浏览器的场景。文中还提供了具体的代码示例。
463 5
在浏览器执行js脚本的两种方式

热门文章

最新文章