Axios Get请求无法接收数据:S3桶内容下载接口返回空对象问题排查
问题分析
你遇到的核心问题是Controller层返回值类型不正确,导致Spring无法正确处理响应输出,进而前端(Postman/浏览器)接收到空对象——而IntelliJ控制台看到的只是服务端本地打印的流对象信息,并非实际返回给前端的有效数据。
当你直接返回ByteArrayOutputStream时,Spring MVC默认会尝试把它当作普通Java对象进行序列化(比如转成JSON),但这个类没有可被序列化的有效业务字段,所以最终返回给前端的就是空对象{}。
解决方案
我们需要修改Controller来返回标准的HTTP响应(包含二进制数据和正确的响应头),同时调整Axios请求逻辑来处理二进制数据流。
1. 修改Controller层代码
把返回值改成ResponseEntity<Resource>,这样可以明确指定响应的内容类型、文件名等信息,Spring会正确输出二进制数据:
import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.core.io.Resource; import org.springframework.web.bind.annotation.GetMapping; @GetMapping(value = "downloadSearchData") public ResponseEntity<Resource> downloadSearchData() throws IOException { ByteArrayOutputStream out = targetLocationService.downloadSearchData(); // 将字节流转换为Spring可识别的资源类型 ByteArrayResource resource = new ByteArrayResource(out.toByteArray()); // 设置响应头,指定下载文件名和内容类型 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"7863784198_2021-08-16T13_30_06.690Z.json\""); return ResponseEntity.ok() .headers(headers) .contentLength(resource.contentLength()) .contentType(MediaType.APPLICATION_JSON) // 因为文件是JSON类型,也可以用通用二进制类型APPLICATION_OCTET_STREAM .body(resource); }
2. 调整Axios请求代码
现在接口返回的是二进制数据流,需要告诉Axios以blob格式接收响应,才能正确处理并生成可下载的文件:
downloadLocations() { axios.get("http://localhost:8080/api/v1/targetLocation/downloadSearchData", { responseType: 'blob' // 关键:指定响应类型为blob,否则会解析成错误的JSON }) .then((res) => { console.log(res.data); // 现在会拿到Blob对象 // 从响应头中提取文件名(和Controller设置的对应) const fileName = res.headers['content-disposition'].split('filename="')[1].split('"')[0]; // 创建下载链接并触发下载 const url = window.URL.createObjectURL(res.data); const link = document.createElement('a'); link.href = url; link.setAttribute('download', fileName); document.body.appendChild(link); link.click(); // 清理临时资源 window.URL.revokeObjectURL(url); document.body.removeChild(link); }, (error) => { console.error(error); }); }
3. Service层代码无需修改
你的Service层从S3获取文件并写入ByteArrayOutputStream的逻辑是正确的,这个部分可以保持原样。
补充说明:为什么IntelliJ控制台能看到输出?
你在Service层打印的System.out.println(out);只是输出了ByteArrayOutputStream对象的内存地址(类似java.io.ByteArrayOutputStream@xxxxxx),并不是实际的文件内容,这和返回给前端的响应没有任何关系。
内容的提问来源于stack exchange,提问作者Tip
相关产品推荐
相关产品推荐

