我想知道安卓系统上是否存在HttpUrlConnection和POST请求的已知问题。当我们从安卓客户端发出帖子请求时,我们正在体验间歇性的 EOFExceptions。重新尝试相同的请求最终将有效。下面是一个示例堆栈跟踪:
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)有许多类似的bug报告和帖子需要堆叠溢出,但我无法理解是否真的存在问题,如果是的话,Android的哪些版本受到影响,以及建议的修复/解决方案是什么。
以下是我所指的一些类似报告:
下面是一个潜在的Android框架修复程序
我知道在前Froyo的连接池中有一个有毒连接的问题,但是这些问题只发生在新的ICS+设备上。如果以后的设备有问题的话,我预计会有一些官方的Android文档来解决这个问题。
发布于 2013-11-30 16:40:06
我们的结论是,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
}发布于 2014-04-03 07:04:11
HttpURLConnection库在内部维护一个连接池。因此,每当发送请求时,它首先检查池中是否已经存在一个现有连接,并根据该连接决定创建一个新连接。
这些连接不过是套接字,默认情况下这个库不会关闭这些套接字。有时可能会发生这样的情况,即当前未使用并存在于池中的连接(套接字)不再可用,因为服务器可能会在一段时间后选择终止连接。现在,由于连接即使被服务器关闭,库也不知道它,并假设连接/套接字仍然连接。因此,它使用这个陈旧的连接发送新请求,因此我们得到了EOFException。
处理此问题的最佳方法是在发送每个请求后检查响应头。服务器总是在终止连接(HTTP1.1)之前发送一个" connection : Close“。因此,您可以使用getHeaderField()并检查"Connection“字段。另外要注意的是,服务器只在即将终止连接时发送此连接字段。因此,在正常情况下(当服务器不关闭连接时),您需要对此进行编码,以获得"null“。
发布于 2014-05-21 22:45:28
这种解决办法往往是可靠的和有表现力的:
static final int MAX_CONNECTIONS = 5;
T send(..., int failures) throws IOException {
HttpURLConnection connection = null;
try {
// initialize connection...
if (failures > 0 && failures <= MAX_CONNECTIONS) {
connection.setRequestProperty("Connection", "close");
}
// return response (T) from connection...
} catch (EOFException e) {
if (failures <= MAX_CONNECTIONS) {
disconnect(connection);
connection = null;
return send(..., failures + 1);
}
throw e;
} finally {
disconnect(connection);
}
}
void disconnect(HttpURLConnection connection) {
if (connection != null) {
connection.disconnect();
}
}此实现依赖于以下事实:可以用服务器打开的默认连接数是5 (Froyo - KitKat)。这意味着可能存在多达5个陈旧的连接,每个连接都必须关闭。
每次尝试失败后,Connection:close请求属性将导致底层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));
}https://stackoverflow.com/questions/19258518
复制相似问题