Android(Java)HttpURLConnection在';阅读';超时

Android(Java)HttpURLConnection在';阅读';超时,java,android,httpurlconnection,android-volley,Java,Android,Httpurlconnection,Android Volley,所以我使用Google-Volley进行HTTP请求,它基本上使用Java的HttpURLConnection 根据我的测试,问题是这样的: 当HttpURLConnection上的“读取”超时达到时,会在连接关闭之前执行静默重试,并引发相关异常(SocketTimeoutException) 注意: -我在使用httppost请求时注意到了这个错误。 -“读取”超时与“连接”超时不同。 -如果“读取”超时(通过调用connection.setReadTimeout(int)设置)未设置(0),

所以我使用
Google-Volley
进行HTTP请求,它基本上使用
Java
HttpURLConnection

根据我的测试,问题是这样的:
HttpURLConnection
上的“读取”超时达到时,会在连接关闭之前执行静默重试,并引发相关异常(
SocketTimeoutException

注意:
-我在使用
httppost
请求时注意到了这个错误。
-“读取”超时与“连接”超时不同。
-如果“读取”超时(通过调用
connection.setReadTimeout(int)
设置)未设置(0),或设置为大于
connection.setConnectTimeout(int)
,则不会发生此错误。
-例如,这个问题已经讨论过了,但我没有找到任何令人满意的解决方案。
-可以找到一个稍微相关的问题,但我不确定它是否相关(是吗?)

更多背景信息
我的应用程序是用来付款的,所以不重试请求是至关重要的(是的,我知道它可以由服务器处理,我希望我的客户端是“正确的”)

设置“读取”超时时,如果建立了服务器连接,但服务器在应答之前等待/休眠/延迟响应该“超时”时间(从而引发“读取”异常而非“连接”异常),则在引发该异常之前发送另一个(静默)请求,导致两个类似的请求,这是不可接受的

我在寻找什么样的解决方案?
好的,这将很好地解决这个问题/bug,就像修复程序所解释的那样(但我再次强调,我认为这与本例无关)。
另外,我希望保持原始流的原样,这意味着不要强迫连接关闭或类似的事情

我现在要做的是,将“读取”超时设置为“连接”超时的两倍(它们同时开始计数),以确保首先引发“连接”异常。我还将尝试在服务器端解决这个问题。问题是,这种“读取”超时是有原因的,而我当前的实现实际上只是忽略了它,只处理“连接”超时

编辑
Volley
库的
RetryPolicy
对该问题没有影响,因为这是一次静默重试。
我尽可能深入地看了看图书馆。到处都有日志/断点,取消了重试调用。这就是我如何知道它是99.99%的一个
HttpURLConnection
问题。

您可以查看Volley的DefaultRetryPolicy类

,您需要将
sun.net.http.retryPost
设置为
false


或者,不要使用固定长度或分块传输模式:请参阅。

好吧,时间过得太久了,所以我想我会用我当前的(不完美的)解决方案回答,让其他人很容易看到它(也写在问题内)

只需将readTimeout设置为0(无超时)或至少设置连接超时值。这将确保在读取超时之前引发连接超时

int timeoutMs = request.getTimeoutMs();    //  or whatever
connection.setConnectTimeout(timeoutMs);   //  actual timeout desired
connection.setReadTimeout(timeoutMs);      //  >= timeoutMs or 0
当然,这取决于请求的使用。大多数情况下,该应用程序是包含相关服务器的项目的一部分,您知道读取超时无论如何都不会发生


如前所述,这不是一个真正的“解决方案”,而是一个非常好且90%有用的修复。

这个糟糕的决定是由一位开发人员在2006年做出的。 下面是一篇很好的引文,作者从java的角度解释了整个情况:

“正如您现在可能猜到的,这是一个bug()。当然不是重试机制,那只是废话。bug是POST也会发生(默认情况下,对于HTTP RFC,它不是幂等的)。但别担心,Bill很久以前就修复了这个bug。Bill通过引入切换来修复它。Bill了解了向后兼容性。Bill决定最好在默认情况下保持切换为“开”,因为这样会使bug向后兼容。Bill微笑着。他已经看到了全球各地惊讶的开发人员的脸上都在运行切换是吗?请不要像比尔那样?“

那么建议的解决方案是:

System.setProperty("sun.net.http.retryPost", "false")
但我们不能在安卓系统上做到这一点!剩下的唯一解决方案是:

httpURLConnection.setChunkedStreamingMode(0);

编辑: 我不能使用这个实现,所以我寻找了一个替代库。 我发现HttpUrlConnection的实现使用的是Android 4.4。由于OkHttp是开源的,我可以搜索他们是否也有静默重试的问题。是的,他们在2016年4月修复了它。(a real)解释说,每个制造商都可以决定他们可以使用哪种实现。因此,一定有很多设备对POST请求进行静默重试,作为开发人员,我们只能尝试一些工作区

我的解决办法是改变图书馆

编辑2:为您提供最终答案:


Thx,但这个问题更深。我检查的第一件事是重试策略,我确实取消了它。此重试是静默的,因此Volley事件不知道它。但是我找不到sun作为依赖项,有什么想法吗?你能解决它吗?这不是一个完美的解决方案,但正如我所说的,当我现在这样做时,将“读取”超时设置为等于或两倍“连接”超时。我会回答我自己,让其他人很容易看到这个解决方案。所以
httpURLConnection.setChunkedStreamingMode(0)
将不会导致重试?请在回答中解释效果:)是的,完全是我想听到的答案……我对建议的解决方案有问题,所以我编辑了答案。请在下面添加我答案的链接。我想它仍然可以帮助其他人。。。另一个解决方案是使用setFixedLengthStreamingMode(contentLength),它解决了您的请求时间透视图。读这个