InputStream 在 spring 控制器中关闭

Posted

技术标签:

【中文标题】InputStream 在 spring 控制器中关闭【英文标题】:InputStream is closed in spring controller 【发布时间】:2019-09-24 11:40:10 【问题描述】:

使用 spring 控制器,端点在正文响应中返回文件。 我想确保不要使用“尝试使用资源”来获取资源泄漏,但是在邮递员中我会收到一个错误:

"error": "内部服务器错误", "message": "流关闭",

Spring控制器中的代码sn-p:

InputStreamResource result;
ResponseEntity<Resource> response;
try(FileInputStream ios = new FileInputStream(file))
    result = new InputStreamResource(ios);
    response = ResponseEntity.ok()
        .headers(/*some headers here*/)
        .contentLength(file.length())
        .contentType(/*some media type here*/)
        .body(result);
    logger.info("successfully created");
    return response;
 catch (IOException e) 
        //some code here..

有趣的是,在日志中我收到了成功消息,但在邮递员或浏览器中(这是一个 GET 请求)我收到了错误。

如果不使用“try-with-resource”,它会起作用,但我担心这样会导致资源泄漏。

【问题讨论】:

我不知道InputStreamResource,但我假设如果该资源关闭,流也将关闭。 【参考方案1】:

因为try with resource会在return之前调用close(),所以会出现“Stream Closed”错误。 一个简单的方法是直接将InputStreamResource 的实例放在.body() 中,网络上的大多数示例也是这样做的。但是,我不确定资源是否会正确关闭以防止应用程序资源泄漏。

response = ResponseEntity.ok()
    .contentLength(file.length())
    .body(new InputStreamResource(new FileInputStream(file)));
return response;

另一种方式,如果你想流式传输响应,你可以使用StreamingResponseBody

Interface StreamingResponseBody(引自 Spring 网站)

这是一个函数式接口,因此可以用作 lambda 表达式或方法引用的赋值目标。

示例代码:

StreamingResponseBody responseBody = outputStream -> 
    Files.copy(file.toPath(), outputStream);
;

response.ok()
    .contentLength(file.length())
    .body(responseBody);
return response;

【讨论】:

我想ResourceHttpMessageConverter 关闭了流:***.com/questions/48660011/…

以上是关于InputStream 在 spring 控制器中关闭的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 InputStream 和 Spring 发送带附件的电子邮件?

Spring Boot RestController - PostMapping - 将请求正文作为 InputStream [重复]

spring boot — InputStream

Spring获取资源文件+从File+从InputStream对象获取正文数据

如何以编程方式取消从 InputStream 中读取?

Mysql 连接器在 com.mysql.jdbc.utils.ReadAhead InputStream.fill() 中花费 50% 的时间