You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 21:48:00