Spring文件POST(JSON)下载, restTemplate.execute大文件流处理

java下载接口

@PostMapping(value = "/download") public void download(@RequestBody DownloadReq req, HttpServletRequest request, HttpServletResponse response) {          // 省略..........      String path = new File(path).getAbsolutePath() + File.separator + req.getFileName();     File file = new File(path);     if (!file.exists()) {         LOGGER.info("file:{}", file.getAbsolutePath());         LOGGER.info("下载文件不存在");     }     response.reset();     response.setContentType("application/octet-stream");     response.setCharacterEncoding("utf-8");     response.setContentLength((int) file.length());     String fileInfoHear = String.format("attachment;filename=%s", req.getFileName());     response.addHeader("Content-Disposition", fileInfoHear);     String origin = request.getHeader("Origin");     response.addHeader("Access-Control-Allow-Origin", origin);     response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");     response.addHeader("Access-Control-Allow-Headers", "Content-Type");     response.addHeader("Access-Control-Allow-Credentials", "true");     // 让浏览器能访问到其它响应头     response.addHeader("Access-Control-Expose-Headers","Content-Disposition");       try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {         byte[] buff = new byte[1024];         OutputStream os = response.getOutputStream();         int i = 0;         while ((i = bis.read(buff)) != -1) {             os.write(buff, 0, i);             os.flush();         }         LOGGER.info("file:{}, 下载成功", file.getAbsolutePath());     } catch (IOException e) {         LOGGER.error("异常", e);     }     // 只能返回null 或者方法是void, 否则会导致下载流关闭 }  

java调用下载接口

public void download(DownloadReq req, String targetPath) {     Map<String, Object> params = new HashMap<>();     params.put("id", req.getId());      Path targetPathO = Paths.get(targetPath);     //定义请求头的接收类型     RequestCallback requestCallback = request -> {         request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));         // json参数         request.getHeaders().setContentType(MediaType.APPLICATION_JSON);         request.getBody().write(JSON.toJSONString(params).getBytes());     };      ResponseExtractor<Void> responseExtractor = response -> {         //对响应进行流式处理而不是将其全部加载到内存中         Files.copy(response.getBody(), targetPathO, StandardCopyOption.REPLACE_EXISTING);         return null;     };     // 省略代码.....     restTemplate.execute(url, HttpMethod.POST, requestCallback, responseExtractor);     log.info("下载文件:{}, 完成", req.getFileName()); } 

前端调用下载接口

this.loading = true axios({   method: 'post',   url: process.env.VUE_APP_BASE_API + '/download',   data: {       // json参数       id: this.$data.id   },   responseType: 'blob',   onDownloadProgress: (evt) => {     // 对原生进度事件的处理, 会在浏览器下方弹出下载文件框     this.setState({ progress: parseInt((evt.loaded / evt.total) * 100) });   } }).then(response => {   let contentDisposition = response.headers['content-disposition'];  //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;   let filename = contentDisposition.split("filename=")[1];    // 将二进制流转为blob   let data = response.data ;   const blob = new Blob([data], { type: 'application/octet-stream' })   if (window.navigator.msSaveBlobOrOpenBlob) {     // 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件     window.navigator.msSaveBlob(blob, decodeURI(filename))   } else {     // 创建新的URL并指向File对象或者Blob对象的地址     const blobURL = window.URL.createObjectURL(blob)     // 创建a标签,用于跳转至下载链接     const tempLink = document.createElement('a')     tempLink.style.display = 'none'     tempLink.href = blobURL     tempLink.setAttribute('download', decodeURI(filename))     // 兼容:某些浏览器不支持HTML5的download属性     if (typeof tempLink.download === 'undefined') {       tempLink.setAttribute('target', '_blank')     }     // 挂载a标签     document.body.appendChild(tempLink)     tempLink.click()     document.body.removeChild(tempLink)     // 释放blob URL地址     window.URL.revokeObjectURL(blobURL)   } }).finally(() => {   this.loading = false })