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天前
|
XML JSON JavaScript
R JSON 文件
JSON: JavaScript Object Notation(JavaScript 对象表示法)。
47 29
|
2天前
|
JSON 前端开发 中间件
React读取properties配置文件转化为json对象并使用在url地址中
本文介绍了如何在React项目中读取properties配置文件,将其内容转化为JSON对象,并在请求URL地址时使用这些配置。文章详细说明了异步读取文件、处理字符串转换为JSON对象的过程,并提供了一个封装函数,用于在发起请求前动态生成配置化的URL地址。
12 1
|
13天前
|
JSON 前端开发 JavaScript
解析JSON文件
解析JSON文件
41 9
|
13天前
|
JSON 前端开发 JavaScript
JSON文件如何读取?
JSON文件如何读取?
43 5
|
1月前
|
存储 JSON JavaScript
|
2天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
13天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
7天前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。