Spring结合Scala实现文件下载接口报HttpMessageNotWritableException如何解决
问题修复方案
错误根因
Spring 默认没有配置可处理InputStreamResource类型、且适配application/octet-stream的HTTP消息转换器,因此无法将返回的InputStreamResource序列化为响应字节流。
可行解决方案
方案1:替换为Spring默认支持的Resource实现(改动最小,优先推荐)
将InputStreamResource替换为FileSystemResource,Spring 内置的ResourceHttpMessageConverter默认支持该类型的序列化,无需额外配置。
修改后的Scala接口代码如下:
@GetMapping(path = Array("/download")) def downloadFile() : ResponseEntity[Resource] = { val file: File = new File("src/main/scala/testFile.txt") if(file.exists()){ // 替换为FileSystemResource val resource = new FileSystemResource(file) val responseHeaders = new HttpHeaders(); responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=results.txt") responseHeaders.add("Cache-Control", "no-cache, no-store, must-revalidate") responseHeaders.add("Pragma", "no-cache") responseHeaders.add("Expires", "0") ResponseEntity.ok() .headers(responseHeaders) .contentLength(file.length()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); }else{ ResponseEntity.notFound().build() } }
方案2:显式注册ResourceHttpMessageConverter
如果必须使用InputStreamResource,可以在Spring配置类中注册支持application/octet-stream的ResourceHttpMessageConverter,配置示例如下:
@Configuration class WebConfig extends WebMvcConfigurer { @Bean def resourceHttpMessageConverter(): ResourceHttpMessageConverter = { val converter = new ResourceHttpMessageConverter() converter.setSupportedMediaTypes( java.util.Arrays.asList( MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL ) ) converter } }
方案3:使用ByteArrayResource(适合小文件场景)
你代码中注释掉的ByteArrayResource本身也可被正常序列化,取消注释即可使用,仅需要注意大文件场景下该实现会占用较多堆内存,不推荐使用。
前端代码补充修正
你当前的XHR请求没有指定响应类型为Blob,会导致前端拿到的响应为文本格式,最终下载的文件损坏,需要在downloadFile方法中补充responseType配置:
function downloadFile(url, success) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); // 新增这行指定响应为二进制Blob xhr.responseType = 'blob'; xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (success) success(xhr.response); } }; xhr.send(null); }
内容的提问来源于stack exchange,提问作者Dulanga Heshan
相关产品推荐
相关产品推荐

