连接到 (...) 泄漏了。你是否忘记关闭响应体?

25

尽管我的代码看起来很不错,但我一直收到警告信息。这个消息是:

WARNING: A connection to http://someurl.com was leaked. Did you forget to close a response body?
java.lang.Throwable: response.body().close()
    at okhttp3.internal.platform.Platform.getStackTraceForCloseable(Platform.java:148)
    at okhttp3.RealCall.captureCallStackTrace(RealCall.java:89)
    at okhttp3.RealCall.execute(RealCall.java:73)
    at com.example.HTTPSClientReferenceRate.runClient(HTTPSClientReferenceRate.java:78)
    at com.example.HTTPSClientReferenceRate.main(HTTPSClientReferenceRate.java:137)

我正在使用Java 8。我尝试过传统的try-catch,也尝试了这种方法(try-with-resources):

我使用Java 8,曾尝试传统的try-catch方法,同时也使用了try-with-resources方法:

boolean repeatRequest = true;

while(repeatRequest) {
    Call call = client.newCall(request);
    try (Response response = call.execute()){
        if (!response.isSuccessful()) {
            log.error("Error with the response: " + response.message());
            continue;
        }
        ResponseBody body = response.body();
        if (body == null){
            log.error("Error when getting body from the response: " + response.message());
            continue;
        }
        BufferedReader br = new BufferedReader(body.charStream());

        //...DATA HANDLING

    } catch (Exception e) {
        log.error("Error Connecting to the stream. Retrying... Error message: " + e.getMessage());
    }
}
事实上,第一个if语句从未被调用,我总是遇到异常,因此我不明白为什么响应/正文没有被try-with-resources块关闭。
我也尝试了这个选项,但它也没有起作用:
try (Response response = client.newCall(request).execute()) { ... }

编辑

我缩减了我的代码,但是仍然遇到相同的错误,这甚至更奇怪:

boolean repeatRequest = true;

while(repeatRequest) {
    Call call = client.newCall(request);
    try (Response response = call.execute()){
        //NOTHING
    } catch (Exception e) {
        log.error("Error Connecting to the stream. Retrying... Error message: " + e.getMessage());
    }
}

编辑2::

我已经尝试使用传统的try-catch,但仍然遇到相同的问题:

boolean repeatRequest = true;

while(repeatRequest) {
    Call call = client.newCall(request);
    Response response = null;
    try {
        response = call.execute();
        try (ResponseBody body = response.body()) {
            //Nothing...
        }
    } catch (Exception e) {
        log.error("Error Connecting to the stream. Retrying... Error message: " + e.getMessage());
    } finally {
        if (response != null){
            response.close();
        }
    }
}

尝试这样做:try (Response response = client.newCall(request).execute()) { - brijesh
@btreport 我之前尝试过,但没有成功,我会在我的帖子描述中添加它。 - Villat
@ErHarshRathore,try-with-resources是在Java 7中添加的,所以这不是问题所在。 - Villat
try(声明+定义){}特性是Java 9中首次引入的。 - Er. Harsh Rathore
@Villat 是的,我有点困惑。抱歉。 - Er. Harsh Rathore
显示剩余4条评论
2个回答

15
根据 Response.close() javadoc 的说明:

关闭一个没有body的响应会导致错误。这包括从 cacheResponsenetworkResponsepriorResponse() 返回的响应。

根据 Github评论,您的代码应该像下面这样编写:
while (repeatRequest) {
    Call call = client.newCall(request);
    Response response = call.execute();
    try (ResponseBody body = response.body()) {
        ...
    }
}

Karol,我编辑了我的帖子,你可以看到错误似乎出现在其他地方,有什么想法吗? - Villat
1
你正在使用 try-with-resource 块关闭 Response。文档表示对于某些响应不要这样做,请尝试在 Github 上建议的代码。 - Karol Dowbecki
@Villat,你使用的OkHttp版本是多少? - Karol Dowbecki
我正在使用3.10.0版本,我也尝试了3.14.2和4.0.1版本,但没有成功。 - Villat
我使用Retrofit,它应该自动关闭所有东西。 - user924
显示剩余4条评论

0

使用 Kotlin 时,如果 response.body 不为空,则可以轻松处理。如果存在 body,则关闭它将关闭源,但如果不存在,则不需要关闭。例如:

                    val response = client.newCall(request).execute()
                    // check for response.isSuccessful here, or read the body if required
                    response.body?.close()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接