前端下载文件流,设置返回值类型responseType:‘blob‘无效的问题

本文讲述了作者在使用VueAxios下载文件时遇到的问题,后经排查发现Mock模块的responseType设置影响了Blob格式的正确接收。作者分享了解决方案和优化下载逻辑的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

本是一个非常简单的请求,即是下载文件。通常的做法如下:

1.前端通过Vue Axios向后端请求,同时在请求中设置响应体为Blob格式。

2.后端相应前端的请求,同时返回Blob格式的文件给到前端(如果没有步骤1设置响应体,则后端返回的是一个文件流,前端)

3.前端创建a标签进行下载

提示:如果后端返回的是文件的地址,那么前端可以直接通过window.location.href加文件路径即可下载文件。但是如果后台返回的是文件流,那么前端就需要做一些处理。处理的核心也是将文件流转成文件,然后使用a标签模拟点击下载。

找出问题 && 解决问题

我遇到的问题也是我想写篇文章记录一下的原因,因为下载文件这样的需求我都写烂了都,觉得这是得心应手的事情,在跟后端对接的时候,我非常坚定是后台返回流有问题(后面打脸了...)

这里我贴上我下载文件实现代码:

1.请求API

重点设置: responseType: 'blob' 

2.封装的异步请求

3.调用接口,拿到返回值,模拟超链接点击下载文件

以上步骤似乎感觉是妥妥的了,但是我在自测的时候,一整个人蒙住,文件直接是打不开

然后我看控制台的输出,一看,不对劲啊,经过转换应该返回正常的blob格式才对,却是如下:

正式因为如此,导致下载下来的是一个无效的文件。

然后开始进一步的排查,代码都被我看烂了,也没看出来哪里会不对劲,各种百度也都试了,就是没有发现有什么问题。最后也是很突然的,我看到有个博主的文章,真的起到醍醐灌顶的作用,文章其中一句“mock模块会影响原生的ajax请求,使得服务器返回的blob类型变成乱码”,我才惊愕,因为我在项目中却是用到了mock,打开控制台发现,mockjs初始化的时候给拦截响应设置了responseType:'',证据如下:

 终于找到原因了,同时把mock注释掉就可以了。真的是怎么也没有想到是mock模块影响了,可是花了好长一段时间去排查这个问题呢,解决了就好呀!!

下面是正常后拿到的数据格式:

优化

tip:我们可以把模拟a标签下载文件这个逻辑封装起来,如果后面又下载文件的需求的时候,可以直接拿来用即可。

1.封装:获取文件流转成文件,并模拟点击该文件,实现下载

​​​​​​​

2.使用

### Java 后端返回 Blob 类型工作流实现 为了实现在 Java 后端返回 Blob 类型数据,可以采用 `javax.servlet.ServletOutputStream` 来将文件写入到 HTTP 响应的输出流中,并通过设置响应头中的 `Content-Type` 和其他必要头部信息来告知客户端即将接收的是二进制流形式的内容[^1]。 #### 设置响应头 在向客户端发送实际的数据之前,先配置好 HttpServletResponse 对象的相关属性。这包括但不限于指定 MIME 类型 (`application/octet-stream`) 表明这是一个通用的二进制流;以及提供下载时建议保存的名字(如果适用)。此外还可以考虑加入 Content-Disposition 头部用于控制浏览器行为,比如提示用户保存附件而不是直接打开。 ```java response.setContentType("application/octet-stream"); String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", fileName); response.setHeader(headerKey, headerValue); ``` #### 获取并读取 BLOB 数据 假设已经有一个数据库连接可用,则可以通过 JDBC API 访问存储于其中的大对象 (BLOB),接着利用 InputStream 将其加载至内存以便后续操作: ```java PreparedStatement pstmt = null; ResultSet rs = null; try { String sql = "SELECT file_data FROM documents WHERE id=?"; pstmt = conn.prepareStatement(sql); pstmt.setInt(1, documentId); // Replace with actual ID value. rs = pstmt.executeQuery(); if(rs.next()){ Blob blob = rs.getBlob("file_data"); try(InputStream inputStream = blob.getBinaryStream()) { ... } } } finally { closeResources(pstmt, rs); } ``` #### 输出 BLOB 至 ServletOutputStream 最后一步就是把从数据库里取出的信息传递给前端应用了。这里会创建一个缓冲区用来临时存放部分字节序列,在循环体内不断填充直至完成整个传输过程为止。需要注意的是应当始终记得关闭资源以防止潜在泄漏问题的发生。 ```java byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead = -1; ServletOutputStream outputStream = response.getOutputStream(); while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush(); inputStream.close(); outputStream.close(); ``` 上述代码片段展示了完整的流程:准备阶段设定了必要的HTTP协议参数;执行查询语句取得目标记录内的大字段内容;再经由服务器容器提供的API接口逐块写出直到结束。此方式适用于大多数场景下的文件分发需求。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值