java.io.IOException:在Android上连接流意外结束

32

我有一个Web服务URL,它运行良好并提供JSON数据。

但当我使用HttpURLConnectionInputStream时,出现以下错误:

java.io.IOException: unexpected end of stream on
Connection{comenius-api.sabacloud.com:443, proxy=DIRECT
hostAddress=12.130.57.1
cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 protocol=http/1.1}
(recycle count=0)

我的代码:

try {
    URL url = new URL("https://comenius-api.sabacloud.com/v1/people/username=" + username + ":(internalWorkHistory)?type=internal&SabaCertificate=" + certificate);

    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    InputStream ist = con.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(ist));

    while ((singleLine = reader.readLine()) != null) {
        data = data + singleLine;
        Log.e("Response", data);
    }

} catch (Exception e) {
    e.printStackTrace();
}

如何解决这个问题?


3
无法完成。这是服务器错误。 - Cătălin Florescu
有其他的解决方案吗? - phaneendra tatapudi
尝试使用OkHttp。它有时对我有效,但我不能保证。 - Cătălin Florescu
@phaneendratatapudi 如何解决这个错误? - prakash ubhadiya
有些用户可能也在寻找从服务器解决相同问题的方法,那么有没有关于从服务器端解决它的建议呢?在我的情况下,我正在寻找在nodejs服务器上的解决方案。 - Sagar Devkota
显示剩余3条评论
12个回答

45

我使用OKHttp3时遇到了同样的问题。问题是每个请求我没有关闭连接,对于客户端来说仍然可用,但对于服务器来说不可用,因此服务器会返回错误。

解决方法是在每个请求完成时指示关闭连接。您需要在头部添加一个标志来指示这一点。在OKHttp3中,如下所示:

Request request = new Request.Builder()
                             .url(URL)
                             .header("Connection", "close")
                             ...

4
这就是答案。对我来说完美地运作了!!我已经寻找了几个小时。 - Ivan
我有一个带有Request对象作为参数的方法。必须使用以下代码片段代替 >> request.addHeader("Connection", "close"); - Tarun
添加 Connection: Close 头部信息后,我又遇到了另一个错误 (javax.net.ssl.SSLException: Write error: ssl=0x7b730be688: I/O error during system call, Broken pipe)。 - Cullub
建议在客户端关闭连接应该被视为一种解决方法,但请记住这会降低整体性能。 - Nolan Amy
1
哇!这个答案真是救了我们的一天!我们使用Apache NiFi与TOTVS Protheus ERP进行集成。NiFi运行InvokeHTTP进程,而Protheus返回了这个错误信息。所以我们在InvokeHTTP处理器属性中添加了一个名为"connection"的属性,内容为"close",结果就像魔法一样解决了问题!非常感谢你! - Guilherme Bigois
显示剩余2条评论

11

保持连接(Keepalive)使客户端难以确定一个响应在哪里结束,下一个响应从哪里开始。1

看起来这个问题是由于在重复使用保活连接时出现了冲突:

  1. 服务器在响应头中没有发送Content-Length

  2. (流式内容的情况下,无法使用Content-Length) 服务器未使用分块传输编码(Chunked transfer encoding)

所以如果你观察到异常,请嗅探HTTP头(例如在Android Studio Profiler工具中)。如果您在响应头中同时看到以下两个:

  • "Connection: keep-alive"

和没有

  • "Content-Length: ***" 或 "Transfer-Encoding: chunked" 头,

那么就是上述的情况。

由于这完全是服务器问题,解决方案应该是在服务器端计算Content-Length并将其放入响应头(或使用分块传输编码,如果可能的话)。

建议在客户端关闭连接只作为一种解决方法,需要考虑它会降低整体性能。


3
听起来很有希望,但我检查了我的头部信息,发现我有 Connection: keep-aliveTransfer-Encoding: chunked。我仍然遇到了这个问题。 - Cullub
你无法观察套接字连接,现在,Android Studio网络分析仅支持OkHttp和HttpURLConnection。 - Setmax

11
今天我遇到了这个问题。结果发现是服务器的问题,因为服务器在解析请求时抛出了一个错误并关闭了。
检查一下你的后端,如果不是你的,通知服务器的所有者。

3
服务器“抛出” - CaptainCrunch

3

我有同样的问题,结果发现虚拟机上仍然存在代理配置,但我已经关闭了Charles。


3

刚刚找到了解决方法
问题实际上是服务器端的问题,而解决方法是发送"content-length"头部信息
如果您使用的是php,请将您的代码设置成以下形式

<?php
ob_start();
// the code - functions .. etc ... example:
$v = print_r($_POST,1);
$v .= "\n\r".print_r($_SERVER,1);
$file = 'file.txt';
file_put_contents($file,$v);
print $v;


// finally
$c = ob_get_contents();
$length = strlen($c);
header('Content-Length: '.$length);
header("Content-Type: text/plain");
//ob_end_flush(); // DID NOT WORK !!
ob_flush()
?>

这里使用的技巧是通过输出缓冲区发送content-length头。

1
这确实是一个服务器端的问题,但是这里没有证据表明服务器使用PHP。 - user207421
我明白你的意思,对于任何误解我感到抱歉,我会编辑我的答案。 - Alaa Morad

1
如果您正在使用带有Ktor客户端(例如使用kotlin多平台)的OkHttp,请考虑启用OkHttp的retryOnConnectionFailure配置参数(在其他环境中可能默认启用)。
根据文档,这将使客户端可以静默恢复以下情况:

过时的池化连接。 ConnectionPool重用套接字以减少请求延迟,但这些连接偶尔会超时。

import io.ktor.client.*
import io.ktor.client.engine.okhttp.*

HttpClient(OkHttp) {
    engine {
        config {
            retryOnConnectionFailure(true)
        }
    }
}

转载自


似乎默认已启用。 - bompf
@bompf 谢谢 - 看起来是 Ktor 导致它被禁用了;答案已更新。 - Nolan Amy

0
我正在使用XAMPP本地主机测试我的应用程序,但出现了这个错误。问题在于我正在使用Skype占用了443端口,我只需退出Skype即可解决错误!

0

我有同样的问题。这个错误是由于服务器端只支持http2引起的。您需要更新JDK到支持http2的版本(>=jdk9)来解决此问题。


0

这是一个服务器错误。这意味着执行在服务器未发送实际响应头的情况下返回到了客户端。

如果您控制服务器代码,请检查处理请求后,您是否显式地发送了带有响应代码的响应头。这样,Retrofit 就知道请求已被处理。


0
在你的 Rest Api 端点中添加 "Connection: keep-alive"
 @Headers({"Content-Type: application/json", "Accept: application/json", "Connection: keep-alive"})

如果您的端点被连续调用


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