Spring Boot如何在HTTP响应体中同时返回文件与元数据且格式为application/json
问题根因
报错的根本原因是:直接返回
Resource时Spring MVC会调用专门的ResourceHttpMessageConverter处理流输出,但你将Resource放入自定义对象后,框架会使用Jackson的JSON序列化器处理对象,而Resource内部持有的BufferedInputStream没有对应的Jackson序列化器,因此抛出异常。要满足返回
application/json格式的要求,只能将二进制文件内容转为JSON支持的文本格式,行业通用方案是将文件内容编码为Base64字符串后和元数据一起返回。
实现方案
1. 定义自定义响应结构体
先创建DTO类统一封装元数据和文件内容:
// 没有lombok的话自行补充Getter/Setter方法 @Data public class FileDownloadResponse { // 以下为自定义元数据字段,可根据业务需求增减 private String fileName; private Long fileSize; private String fileType; private String uploadUser; // Base64编码后的文件内容 private String fileContent; }
2. 改造接口逻辑
将Resource的二进制内容读取后编码为Base64字符串,再组装响应返回:
@ResponseBody @GetMapping("/download/{filename}") public ResponseEntity<FileDownloadResponse> downloadFile(@PathVariable String filename) { Resource resource; try { resource = resourceService.getResource(filename); } catch (FileNotFoundException e) { return ResponseEntity.notFound().build(); } try { // 读取文件字节流 byte[] fileBytes = StreamUtils.copyToByteArray(resource.getInputStream()); // 编码为Base64字符串 String base64Content = java.util.Base64.getEncoder().encodeToString(fileBytes); // 组装响应对象 FileDownloadResponse resp = new FileDownloadResponse(); resp.setFileName(filename); resp.setFileSize(resource.contentLength()); resp.setFileType(Files.probeContentType(Paths.get(resource.getFilename()))); resp.setFileContent(base64Content); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(resp); } catch (IOException e) { return ResponseEntity.internalServerError().build(); } }
注意事项
- 该方案不适合大文件场景:Base64编码会让文件体积膨胀约33%,过大的文件会导致内存占用过高、响应超时
- 客户端拿到响应后,需要将
fileContent字段的Base64字符串解码后才能得到原始文件内容 - 低版本Java环境如果没有
java.util.Base64工具类,可替换为org.apache.commons.codec.binary.Base64的相关实现
内容的提问来源于stack exchange,提问作者Rikkert
相关产品推荐
相关产品推荐

