java - Android 网络调用有时会卡在 IOException :java.net.SocketTimeoutException: timeout
问题描述
我有一个应用程序可以上传一些文件(png、mp4)。完整的堆栈是它背后的 Nginx + Node 服务器。有时,当互联网出现问题时,似乎一些用户在生产中遇到了奇怪的行为,然后 Android 应用程序无法发送进一步的上传请求,因为他们都得到 :
IOException : java.net.SocketTimeoutException: timeout
。
然而,最奇怪的是我们看到服务器确实发送了响应(409 冲突,意味着正在上传的文件已经存在并完成上传),但 Android 应用程序根本没有收到这些响应,只是继续尝试上传那些文件,但连接不断失败,因为 SocketTimeoutException 一次又一次,而不是收到 409 响应。
然后,一段时间后,它恢复正常,突然可以收到 409 响应并继续,好像一切都很好。
我尝试使用最基本的 HttpUrlConnection 以及 Square 的 OkHttp 库,但结果相同。
当我使用 Okhttp + HTTP/2 + 代理对其进行调试以监视请求时,在帧日志记录中我看到(启用了代理):
02-16 13:30:16.047 2719 6597 D okhttp.Http2: << 0x00000003 4 RST_STREAM
02-16 13:30:16.049 2719 3758 D okhttp.TaskRunner: Q10117 canceled : OkHttp ConnectionPool
02-16 13:30:16.051 2719 6597 D okhttp.Http2: >> 0x00000000 8 GOAWAY
02-16 13:30:16.051 2719 6597 D okhttp.TaskRunner: Q10121 finished run in 60 s : <our server>
此时我的代码已经收到来自我的服务器实现的错误。然后我看到:
02-16 13:30:20.129 2719 3758 D okhttp.Http2: >> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
02-16 13:30:20.131 2719 3758 D okhttp.Http2: >> 0x00000000 6 SETTINGS
02-16 13:30:20.132 2719 3758 D okhttp.Http2: >> 0x00000000 4 WINDOW_UPDATE
02-16 13:30:20.133 2719 3758 D okhttp.TaskRunner: Q10157 scheduled after 0 µs: OkHttp <our server>
02-16 13:30:20.135 2719 3758 D okhttp.TaskRunner: Q10153 scheduled after 0 µs: OkHttp ConnectionPool
02-16 13:30:20.135 2719 7381 D okhttp.TaskRunner: Q10157 starting : OkHttp <our server>
02-16 13:30:20.136 2719 7365 D okhttp.TaskRunner: Q10153 starting : OkHttp ConnectionPool
02-16 13:30:20.137 2719 7365 D okhttp.TaskRunner: Q10153 run again after 300 s : OkHttp ConnectionPool
02-16 13:30:20.137 2719 7365 D okhttp.TaskRunner: Q10153 finished run in 1 ms: OkHttp ConnectionPool
02-16 13:30:20.138 2719 3758 D okhttp.Http2: >> 0x00000003 1063 HEADERS END_HEADERS
02-16 13:30:20.145 2719 7381 D okhttp.Http2: << 0x00000000 18 SETTINGS
02-16 13:30:20.146 2719 7381 D okhttp.TaskRunner: Q10154 scheduled after 0 µs: OkHttp <our server> applyAndAckSettings
02-16 13:30:20.147 2719 7381 D okhttp.Http2: << 0x00000000 4 WINDOW_UPDATE
02-16 13:30:20.147 2719 7365 D okhttp.TaskRunner: Q10154 starting : OkHttp <our server> applyAndAckSettings
02-16 13:30:20.149 2719 7365 D okhttp.TaskRunner: Q10156 scheduled after 0 µs: OkHttp <our server> onSettings
02-16 13:30:20.151 2719 6597 D okhttp.TaskRunner: Q10156 starting : OkHttp <our server> onSettings
02-16 13:30:20.151 2719 6597 D okhttp.TaskRunner: Q10156 finished run in 1 ms: OkHttp <our server> onSettings
02-16 13:30:20.152 2719 7365 D okhttp.Http2: >> 0x00000000 0 SETTINGS ACK
02-16 13:30:20.153 2719 3758 D okhttp.Http2: >> 0x00000003 65535 DATA
02-16 13:30:20.153 2719 7365 D okhttp.TaskRunner: Q10154 finished run in 6 ms: OkHttp <our server> applyAndAckSettings
02-16 13:30:20.156 2719 3758 D okhttp.Http2: >> 0x00000003 1 DATA
02-16 13:30:20.231 2719 7381 D okhttp.Http2: << 0x00000000 0 SETTINGS ACK
按照@Yuri Schimke 的建议,我添加了 PrintingEventListener,这就是我得到的:
2021-02-17 09:18:50.056 28203-28286/<package name> I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
2021-02-17 09:18:53.378 28203-28286/<package name> I/System.out: 0.000 callStart
2021-02-17 09:18:53.460 28203-28286/<package name> I/System.out: 0.081 proxySelectStart
2021-02-17 09:18:53.462 28203-28286/<package name> I/System.out: 0.084 proxySelectEnd
2021-02-17 09:18:53.462 28203-28286/<package name> I/System.out: 0.084 dnsStart
2021-02-17 09:18:53.463 28203-28286/<package name> I/System.out: 0.085 dnsEnd
2021-02-17 09:18:53.475 28203-28286/<package name> I/System.out: 0.096 connectStart
2021-02-17 09:18:53.650 28203-28286/<package name> I/System.out: 0.271 secureConnectStart
2021-02-17 09:18:53.796 28203-28286/<package name> I/System.out: 0.418 secureConnectEnd
2021-02-17 09:18:53.834 28203-28286/<package name> I/System.out: 0.456 connectEnd
2021-02-17 09:18:53.839 28203-28286/<package name> I/System.out: 0.461 connectionAcquired
2021-02-17 09:18:53.870 28203-28286/<package name> I/System.out: 0.492 requestHeadersStart
2021-02-17 09:18:53.891 28203-28286/<package name> I/System.out: 0.513 requestHeadersEnd
2021-02-17 09:18:53.891 28203-28286/<package name> I/System.out: 0.513 requestBodyStart
2021-02-17 09:19:03.382 28203-28286/<package name> I/System.out: 10.003 requestFailed
2021-02-17 09:19:03.391 28203-28311/<package name> I/System.out: 10.012 canceled
2021-02-17 09:19:03.399 28203-28286/<package name> I/System.out: 10.021 connectionReleased
2021-02-17 09:19:03.400 28203-28286/<package name> I/System.out: 10.022 callFailed
解决方案
暂时忽略您的具体问题。第一个挑战是提出一个 Stackoverflow 响应者可以轻松帮助您取得进展的问题。这里的每个人都想帮助你的问题。
阅读https://stackoverflow.com/help/how-to-ask和http://sscce.org
对于 OkHttp,使用它提供的调试工具来获取解释正在发生的事情的额外数据,即使它不是立即清楚。您是否要返回多条路线,而第一条路线很慢,然后被标记为坏路线?
事件记录 - https://square.github.io/okhttp/events/
HTTP/2 帧日志记录(如果可以启用)- https://square.github.io/okhttp/debug_logging/#http2-frame-logging
运行调试器并捕获正在发生的事情的堆栈跟踪?IO 线程是否仍在读取和阻塞网络?
推荐阅读
- c# - 如何在 PlayerPrefs 中将秒转换为分钟
- rust - Rust 中的 let Foo(bar) = zar 是什么?
- javascript - 如何在 Spacemacs 中为 javascript 自动完成显示键入案例的所有匹配关键字
- amazon-web-services - 使用 boto3 从 dynamoDB 写入和检索最新条目
- java - 如何在 JAR 文件中隐藏密码
- html - 链接 SVG 图像的最佳方式是什么?
- python - Python 语法是否会阻止我创建此列表理解?
- reactjs - 使用 Jest 进行 React 快照测试,子组件如何从父组件调用函数?
- excel - 检查单元格是否为文本,如果是,则删除行
- git - 如何在改编文件上使用 git?