java.io.IOException:尝试从封闭流中读取

时间:2013-09-05 12:14:40

标签: java jackson apache-httpclient-4.x

我正在使用Apache HTTP Client进行HTTPPost调用,然后我尝试使用Jackson从响应中创建一个对象。 这是我的代码:

private static final Logger log = Logger.getLogger(ReportingAPICall.class);
ObjectMapper mapper = new ObjectMapper();

public void makePublisherApiCall(String jsonRequest)
{
    String url = ReaderUtility.readPropertyFile().getProperty("hosturl");
    DefaultHttpClient client = new DefaultHttpClient();
    try {
        HttpPost postRequest = new HttpPost(url);
        StringEntity entity = new StringEntity(jsonRequest);
        postRequest.addHeader("content-type", "application/json");
        log.info("pub id :"+ExcelReader.publisherId);
        postRequest.addHeader("accountId", ExcelReader.publisherId);
        postRequest.setEntity(entity);
        HttpResponse postResponse = client.execute(postRequest);
        log.info(EntityUtils.toString(postResponse.getEntity()));

    //  Response<PublisherReportResponse> response = mapper.readValue(postResponse.getEntity().getContent(), Response.class);
    //  log.info("Reponse "+response.toString());
    } catch (UnsupportedEncodingException ex) {
        log.error(ex.getMessage());
        log.error(ex);
        Assert.assertTrue(false, "Exception : UnsupportedEncodingException");
    } catch (ClientProtocolException ex) {
        log.error(ex.getMessage());
        log.error(ex);
        Assert.assertTrue(false, "Exception : ClientProtocolException");
    } catch (IOException ex) {
        log.error(ex.getMessage());
        log.error(ex);
        Assert.assertTrue(false, "Exception : IOException");
    }

方法makePublisherApiCall()将在循环中调用,该循环运行100次。 当我取消注释该行时,基本上会出现问题:

//  Response<PublisherReportResponse> response = mapper.readValue(postResponse.getEntity().getContent(), Response.class);
//  log.info("Reponse "+response.toString());

取消注释后,我得到例外:

Attempted read from closed stream.
17:26:59,384 ERROR com.inmobi.reporting.automation.reportingmanager.ReportingAPICall - java.io.IOException: Attempted read from closed stream.

否则它工作正常。 有人可以让我知道我做错了什么。

6 个答案:

答案 0 :(得分:31)

EntityUtils.toString(postResponse.getEntity())对响应实体做了什么?我怀疑它正在消耗实体的内容流。 HttpClient javadoc状态,只有可重复的实体可以被多次使用。因此,如果实体不可重复,则无法再次将内容流提供给映射器。为避免这种情况,您应该只让映射器使用流 - 如果需要记录内容,请记录已解析的Response对象。

答案 1 :(得分:3)

我遇到了同样的问题。确保您没有在IDE的“监视”或“检查”部分中使用实体的内容流。它被消耗(阅读)后关闭。

抱歉我的英语。

答案 2 :(得分:1)

我遇到了同样的问题。

这个想法是,如果你使用postResponse,那么你应该把它放在一个变量中,以便在不同的地方再次使用它。 否则,连接已关闭,您再也无法再使用相同的响应。

我曾经记录它(出于调试目的)并且总是失败。

答案 3 :(得分:0)

我认为此问题与任何回应均无关, 我收到此问题是因为我没有使用

closeableresponce=client.Getmethod(FinalUrl);

在我的第一个Test1中,提到了它,但是当我错过了Test2时,我忘记了放这段代码,这就是为什么流关闭消息显示的原因...

public void getapiwithheader() throws ParseException, IOException
{
    client = new RestClient();
    closeableresponce=client.Getmethod(FinalUrl);

    HashMap<String, String> headermap = new HashMap<>();
    headermap.put("content-type", "application/json");
    //****************************************************************************    
    //Status code
    //****************************************************************************      
    int statuscode =closeableresponce.getStatusLine().getStatusCode();
    System.out.println("Status code "+statuscode);
    Assert.assertEquals(statuscode,RESPONSE_STATUS_CODE_200, "Status code is not 200");


    //****************************************************************************  
    // Json String
    //****************************************************************************      
    String responsestring=  EntityUtils.toString(closeableresponce.getEntity(),"UTF-8");
    JSONObject respjsonobj = new JSONObject(responsestring);
    System.out.println("Respose Json API"+respjsonobj);

    //****************************************************************************      
    // Verify the value of the JSON
    //****************************************************************************      
    String Email =TestUtil.getValueByJPath(respjsonobj,"/email");
    System.out.println("******************************************");
    System.out.println("Print the value of Email "+Email);
    Assert.assertEquals(Email, "johndoe@google.com");
}

答案 4 :(得分:0)

我在这里找到了与Spring RestTemplate类似问题的答案:https://www.baeldung.com/spring-rest-template-interceptor

如果我们希望拦截器充当请求/响应记录器,那么我们需要对其进行两次读取-第一次由拦截器读取,第二次由客户端读取。 默认实现使我们只能读取一次响应流。为了满足这种特定情况,Spring提供了一个特殊的类BufferingClientHttpRequestFactory。顾名思义,此类将请求/响应缓冲在JVM内存中以供多种使用。

以下是使用BufferingClientHttpRequestFactory初始化RestTemplate对象以启用请求/响应流缓存的方法:

RestTemplate restTemplate = new RestTemplate( new BufferingClientHttpRequestFactory( new SimpleClientHttpRequestFactory() ) );

答案 5 :(得分:-1)

我有同样的问题。

对于我来说,我需要通过AOP /

获取响应内容