当前位置:首页 > 系统bug > 正文内容

Android HttpUrlConnection EOFException

2019-06-02 | 分类:系统bug | 评论:0人 | 浏览:164次

我想知道Android上是否存在HttpUrlConnection和POST请求的已知问题。从Android客户端发出POST请求时,我们遇到间歇性的 EOFExceptions。重试相同的请求最终会起作用。这是一个示例堆栈跟踪:eofexception

java.io.EOFException
at libcore.io.Streams.readAsciiLine(Streams.java:203)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:579)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:827)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
有许多类似的错误报告和帖子到堆栈溢出但我无法理解是否确实存在问题,如果是,那么什么版本的Android会受到影响以及建议的修复/解决方法是什么。
我知道在Froyo之前的连接池中存在中毒连接的问题,但这些问题仅在新的ICS +设备上发生。如果以后的设备出现问题,我会期待某种官方Android文档的问题。
 
 
 

我们的结论是Android平台存在问题。我们的解决方法是捕获EOFException并重试请求N次。下面是伪代码:

private static final int MAX_RETRIES = 3;

private ResponseType fetchResult(RequestType request) {
    return fetchResult(request, 0);
}

private ResponseType fetchResult(RequestType request, int reentryCount) {
    try {
        // attempt to execute request
    } catch (EOFException e) {
        if (reentryCount < MAX_RETRIES) {
            fetchResult(request, reentryCount + 1);
        }
    }
    // continue processing response
}

 

我正在尝试这个,但它不起作用。我想验证您的伪代码如下:1。通过url.openConnection()打开连接。2.如果在调用getResponseCode()时获得EOF,则断开连接,将HttpURLConnection设置为null并再次连接。3.尝试此操作直到最大重试次数。每次尝试请求时,我都会建议您重新创建HttpURLConnection,不要尝试重用相同的实例

    您能否发布有关您遇到的问题的更多详细信息。无论您尝试多少次,您是否只是反复获得EOF异常?您正在测试哪些设备/版本的Android? 它现在正在运行,没有代码更改,很奇怪……但现在我的SSL引擎正在崩溃。不同的问题,但感谢您的帮助。

    image

     

     

     

HttpURLConnection库在内部维护一个Connections池。因此,每当发送请求时,它首先检查池中是否存在现有连接,基于该连接它决定创建新连接。

这些连接只是套接字,默认情况下此库不会关闭这些套接字。有时可能会发生当前未使用且存在于池中的连接(套接字)不再可用,因为服务器可能会选择在一段时间后终止连接。现在,由于连接即使由服务器关闭,库也不知道它并假设连接/套接字仍然连接。因此它使用这个陈旧的连接发送新请求,因此我们得到EOFException。

处理此问题的最佳方法是在发送每个请求后检查响应标头。服务器始终在终止连接(HTTP 1.1)之前发送“连接:关闭”。因此,您可以使用getHeaderField()并检查“连接”字段。另一件需要注意的事情是,服务器ONLY在即将终止连接时发送此连接字段。因此,您需要在正常情况下(当服务器未关闭连接时)获得“null”的可能性进行编码

此实现依赖于可以使用服务器打开的默认连接数5(Froyo – KitKat)。这意味着最多可能存在5个过时连接,每个连接都必须关闭。

每次尝试失败后,Connection:closerequest属性将导致底层HTTP引擎在connection.disconnect()调用时关闭套接字。通过重试最多6次(最大连接数+ 1),我们确保始终为最后一次尝试提供新的套接字。

如果没有连接存在,请求可能会遇到额外的延迟,但这肯定比一个更好EOFException。在这种情况下,最终的发送尝试不会立即关闭刚刚打开的连接。这是唯一可以实现的实用优化。

5您可以自己配置系统属性,而不是依赖于神奇的默认值。请记住,这个属性是由KitKat的ConnectionPool.java中的静态初始化程序块访问的,它也适用于旧的Android版本。因此,在您有机会设置之前,可以使用该属性。

static final int MAX_CONNECTIONS = 5;

static {
    System.setProperty("http.maxConnections", String.valueOf(MAX_CONNECTIONS));
}

是。Android平台存在问题,特别是在版本为4.1-4.3的Android libcore中。

此提交中引入了此问题:https//android.googlesource.com/platform/libcore/+/b2b02ac6cd42a69463fd172531aa1f9b9bb887a8

Android 4.4将http lib切换为“okhttp”,没有这个问题。

问题解释如下:

在Android 4.1-4.3,当您使用的URLConnection / HttpURLConnection的以“ChunkedStreamingMode”或“FixedLengthStreamingMode”为POST ,的URLConnection / HttpURLConnection类不会做静默重试,如果重复使用的连接是陈旧的。您应该在代码中最多重试“http.maxConnections + 1”次,就像之前的答案所示。

我怀疑这可能是服务器有问题,并且HttpURLConnection不像其他实现那样宽容。这是我的EOFException的原因。我怀疑在我的情况下这不会是间歇性的(在测试N重试变通方法之前修复它),所以上面的答案与其他问题有关并且在这些情况下是正确的解决方案。

我的服务器使用的是python SimpleHTTPServer,我错误地假设我需要做的就是表明成功如下:

self.send_response(200)

它发送初始响应标题行,服务器和日期标题,但使流处于您能够发送其他标题的状态。HTTP需要在标题之后添加一个新行以表示它们已完成。当你尝试使用HttpURLConnection获取结果体InputStream或响应代码等时,如果这个新行不存在,那么它会抛出EOFException(这实际上是合理的,考虑它)。一些HTTP客户端确实接受了短响应,并报告了成功结果代码,这导致我可能不公平地将手指指向HttpURLConnection。

我改变了我的服务器来做这件事:

self.send_response(200)
self.send_header("Content-Length", "0")
self.end_headers()

该代码不再有EOFException。

来源:赵大虾博客(微信号/QQ号:),转载请注明出处,谢谢!

  • 评论:(0)

已有 0 位网友发表了一针见血的评论,你还等什么?

◎欢迎参与讨论!

傲笑九天志在必得, 卧薪尝胆勇者无畏

站内搜索

傲笑九天志在必得, 卧薪尝胆勇者无畏

傲笑九天志在必得, 卧薪尝胆勇者无畏