Attempted read from closed stream

1、概述

java.lang.RuntimeException: java.io.IOException: Attempted read from closed stream 错误通常表示程序试图从一个已经关闭的流中读取数据。在Java中,一旦一个流被关闭,任何尝试从该流中读取数据的操作都会抛出IOException。

最近使用PowerJob添加工作流管理, 往powerjob_workflow_node_info、powerjob_workflow_info表两个表插入数据,调的是engin-service。报java.io.IOException: Attempted read from closed stream.

工具类代码:


import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Component
@Slf4j
public class PowerjobUtil {

    @Value("${powerjob.ip}")
    private String ip;

    private static HttpClient httpClient;

    public String get(String uri) {
        if (httpClient == null) {
            httpClient = HttpClients.createDefault();
        }
        HttpGet getMethod = new HttpGet("http://" + ip + uri);
        log.info("请求engine-server接口:{},入参:{}", uri);
        getMethod.addHeader("accept", "*/*");
        getMethod.addHeader("connection", "Keep-Alive");
        try {
            HttpResponse response = httpClient.execute(getMethod);
            log.info("请求engine-server接口:{},出参:{}", uri);
            HttpEntity httpEntity = response.getEntity();
            return EntityUtils.toString(httpEntity);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String post(String uri, String requestJson) {
        if (httpClient == null) {
            httpClient = HttpClients.createDefault();
        }
        HttpPost postMethod = new HttpPost("http://" + ip + uri);
        log.info("请求engine-server接口:{},入参:{}", uri, requestJson);
        postMethod.addHeader("Content-Type", "application/json");
        postMethod.addHeader("accept", "*/*");
        postMethod.addHeader("connection", "Keep-Alive");
        postMethod.setEntity(new StringEntity(requestJson, StandardCharsets.UTF_8));
        try {
			HttpResponse response = httpClient.execute(postMethod);
			HttpEntity httpEntity = response.getEntity();
			log.info("请求engine-server接口:{},出参:{}", uri, 		EntityUtils.toString(httpEntity));
			return EntityUtils.toString(httpEntity);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

2、逻辑调用

插入任务管理新后再往PowerJob表同步数据,同步是执行两个方法

#插入任务管理新后再往PowerJob表同步数据
 ResultDTO result = auditTaskService.savePowerjobWorkflowInfo(req);
 if (!result.isSuccess()) {
      log.error("update Task Config sync powerjob_workflow_info fail."+result.getMessage());
      return R.fail(result.getMessage());
  }
  ResultDTO resultInfo = auditTaskService.savePowerjobWorkflowNodeInfo(req);
  if (!resultInfo.isSuccess()) {
      log.error("update Task Config sync powerjob_workflow_node_info fail."+resultInfo.getMessage());
      return R.fail(resultInfo.getMessage());
  }

工具栏里最初返回数据是这样写的:

HttpResponse response = httpClient.execute(postMethod);
HttpEntity httpEntity = response.getEntity();
log.info("请求engine-server接口:{},出参:{}", uri, EntityUtils.toString(httpEntity));
return EntityUtils.toString(httpEntity);

3、分析原因

提供的 post 方法实现,看起来您在使用一个全局的 httpClient 对象来发送HTTP POST请求。这可能会导致流在某个请求完成后被关闭,从而影响到后续的请求。

上述工具类中的 post 方法,是每个请求都创建一个新的 HttpPost 对象。
不要在 post 方法中关闭 httpClient 对象,因为它被设计为可以在多个请求之间重用。然而,根据提示错误信息,问题可能出现在 EntityUtils.toString(httpEntity) 这一行。EntityUtils.toString(httpEntity) 会消耗掉 HttpEntity 中的内容,并且在使用完毕后关闭底层的流。如果您在后续的请求中尝试再次读取这个流,就会遇到 Attempted read from closed stream 的错误。

4、处理方法

要解决这个问题,您可以考虑以下几种方法:
确保 post 方法中的 httpEntity 只被读取一次。
如果需要在多个地方读取 httpEntity 的内容,可以考虑使用 BufferedHttpEntity 来包装原始的 HttpEntity,这样就可以多次读取内容而不会关闭底层的流。
使用 try-with-resources 或者确保在每次请求后都正确关闭 HttpPost 对象,但是不要关闭 httpClient。
最后改成这样就好了。

HttpResponse response = httpClient.execute(postMethod);
HttpEntity httpEntity = response.getEntity();
// 使用BufferedHttpEntity来包装原始的HttpEntity
HttpEntity bufferedHttpEntity = new BufferedHttpEntity(httpEntity);
String responseString = EntityUtils.toString(bufferedHttpEntity);
log.info("请求engine-server接口:{},出参:{}", uri, responseString);
return responseString;
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值