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

Spring中StreamingResponseBody不被识别的问题解决咨询

问题

我希望在Spring控制器中返回StreamingResponseBody以实现响应内容流式传输,代码示例如下:

@RestController
class MyController(MyService service) {
  @PostMapping("/test")
  Object test() {
    return service.data()
  }
}

@Service
class MyService {
  Object data() {
   File file=new File("Path to the pdf file");
   FileInputStream instream=new FileInputStream(file);
   StreamingResponseBody stream = out -> {
     instream.transferTo(out)
   };
   return ResponseEntity
     .ok()
     .contentType(MediaType.parseMediaType("application/pdf"))
     .body(stream)
  }
}

运行时出现异常:

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class deegixl.framework.file.MyService$2$3$$Lambda$1416/0x00000008019d5240] with preset Content-Type 'application/pdf']

该异常表明Spring已识别到ResponseEntity(尽管返回类型为Object),但未识别StreamingResponseBody。

我明确返回ResponseEntity<StreamingResponseBody>可解决问题,但实际场景中MyService有时需返回POJO用于JSON序列化;将文件转为byte[]也可行,但为保障性能需实现流式传输。请问该如何解决此问题?

解决方案

方法1:让Service返回泛型ResponseEntity

修改MyService的返回类型为ResponseEntity<?>,既支持返回带StreamingResponseBody的流式响应,也能返回带POJO的JSON响应:

@Service
class MyService {
  ResponseEntity<?> data() {
    // 场景1:返回流式PDF
    File file = new File("Path to the pdf file");
    try (FileInputStream instream = new FileInputStream(file)) {
      StreamingResponseBody stream = out -> instream.transferTo(out);
      return ResponseEntity.ok()
              .contentType(MediaType.APPLICATION_PDF)
              .body(stream);
    } catch (IOException e) {
      // 场景2:返回错误POJO
      ErrorResponse error = new ErrorResponse("文件读取失败", e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
              .contentType(MediaType.APPLICATION_JSON)
              .body(error);
    }
  }
}

// 控制器直接返回泛型ResponseEntity
@RestController
class MyController(MyService service) {
  @PostMapping("/test")
  ResponseEntity<?> test() {
    return service.data();
  }
}

Spring能明确识别ResponseEntity类型,会根据其内部body的实际类型自动选择对应的处理器,不管是流式响应还是POJO序列化都能正常工作。

方法2:控制器层做类型适配

如果不想改动Service的返回类型(保持返回Object),可以在控制器中对返回值做类型判断,手动转换为带明确泛型的ResponseEntity:

@RestController
class MyController(MyService service) {
  @PostMapping("/test")
  Object test() {
    Object result = service.data();
    if (result instanceof ResponseEntity<?>) {
      ResponseEntity<?> response = (ResponseEntity<?>) result;
      if (response.getBody() instanceof StreamingResponseBody) {
        // 转换为明确泛型的ResponseEntity,让Spring识别流式响应
        return ResponseEntity.status(response.getStatusCode())
                .headers(response.getHeaders())
                .body((StreamingResponseBody) response.getBody());
      }
    }
    // 其他情况直接返回,Spring自动处理POJO序列化
    return result;
  }
}

这种方式无需修改Service代码,仅通过控制器层的类型转换解决识别问题。

方法3:自定义消息转换器(进阶)

如果上述方法无法满足特殊需求,可以自定义HttpMessageConverter,专门处理StreamingResponseBody类型的body,即使返回类型是Object也能被正确识别。不过该方式实现相对复杂,适合有扩展需求的场景。

内容的提问来源于stack exchange,提问作者Javaddict

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:17:09