如何查看 OkHttp 客户端的完整内部工作?改造插座关闭超时
Posted
技术标签:
【中文标题】如何查看 OkHttp 客户端的完整内部工作?改造插座关闭超时【英文标题】:How can i see The full Inner Working of an OkHttp Client? Retrofit Socket Closed Time Out 【发布时间】:2020-05-28 07:04:58 【问题描述】:您好,非常感谢您抽出宝贵时间,我有一个未知的改装问题,我唯一的线索是套接字关闭/超时消息,所以我想我可以帮助我了解更多关于 okhttp 客户端的信息和改造工作,因为我知道套接字必须对 HTTP 客户端做更多的事情,所以我想更多地了解 okhttp 客户端背后的内部工作,因为这可能会导致解决方案。
所以这是我的问题。
我遇到的一个问题是,我的一个回调函数在 android 应用程序上通过 Post 获取一些数据,即使同一 Web 服务中的其他调用稳定且工作正常,我的一个回调也永远不会返回响应正文。这个错误是相当随机的,它只会在 Android 应用程序上使用改造时发生,而使用邮递员或在 Web 浏览器上使用 API 工作得很好。
我能够始终如一地复制错误的唯一方法是将 android 模拟器上的网络类型从 Full 切换到 HSDPA 或任何其他不同于 full 或 LTE 的网络类型。
<blockquote class="imgur-embed-pub" lang="en" data-id="a/8bgCxtr" data-context="false" ><a href="//imgur.com/a/8bgCxtr"></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
这是我通过 Throwable on Failure Calls 得到的一些响应
java.net.SocketTimeoutException: 超时 详细信息:超时
我尝试增加 OkHttp 客户端上的超时,而不是超时错误,我得到一个 Socket Closed。 java.net.SocketException:套接字关闭 详细信息:套接字关闭
除了那些简单的行之外,没有更多关于错误的信息,所以我搜索了一种获取更多信息的方法,我发现我可以在 OkHttp 客户端上设置一个日志拦截器来获取有关该问题的更多信息,但是我得到了什么还不足以让我看到可能的解决方案。
这是我在调用正确返回时得到的日志:
D/OkHttp: --> POST http://192.168.1.68:83/api/Comercios/comercios
D/OkHttp: Content-Type: application/json; charset=UTF-8
D/OkHttp:内容长度:418
D/OkHttp:授权:承载 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfVXNlck5hbWUiOiJVU0VSX0JPTkFOWkExIiwiX0hhc2giOiI1U1FGQUEiLCJqdGkiOiIzNmNmYTZlOS01ODk3LTQ0NjYtYjA0Mi1kZGVkMDBiZGU5ZDAiLCJleHAiOjE1ODE0ODAxMjUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODMiLCJhdWQiOiJNeVRlc3RBcGkifQ.9xAkkMxRpUEFMNdQaZvVTYQIEc-8w22fl_ubIAVaqi4 P>
D/OkHttp: “anyObjects”: “idGrupo”: “00d60025-6fb9-484f-97f0-08d79dfdbf92”, “文化之”: “”, “散列”: “5SQFAA”, “标记”:“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfVXNlck5hbWUiOiJVU0VSX0JPTkFOWkExIiwiX0hhc2giOiI1U1FGQUEiLCJqdGkiOiIzNmNmYTZlOS01ODk3LTQ0NjYtYjA0Mi1kZGVkMDBiZGU5ZDAiLCJleHAiOjE1ODE0ODAxMjUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODMiLCJhdWQiOiJNeVRlc3RBcGkifQ.9xAkkMxRpUEFMNdQaZvVTYQIEc-8w22fl_ubIAVaqi4 ","usuario":"USER_BONANZA1"
D/OkHttp: --> END POST (418-byte body)
D/OkHttp: http://192.168.1.68:83/api/Comercios/comercios (66 毫秒)
D/OkHttp:传输编码:分块
D/OkHttp: Content-Type: application/json;字符集=utf-8
D/OkHttp:服务器:Kestrel
D/OkHttp: X-Powered-By: ASP.NET
D/OkHttp:日期:2020 年 2 月 12 日,星期三,格林威治标准时间 01:03:01
https://pastebin.com/wRwnMrsk2020-02-11 19:02:59.515
D/OkHttp:
响应正文在粘贴箱中,太长,无法出现在此帖子中。
这是调用超时或套接字关闭的时候
D/OkHttp: --> POST http://192.168.1.68:83/api/Comercios/comercios D/OkHttp: Content-Type: application/json;字符集=UTF-8 D/OkHttp: 内容长度:418 D/OkHttp:授权:承载 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfVXNlck5hbWUiOiJVU0VSX0JPTkFOWkExIiwiX0hhc2giOiJCRFo1R0EiLCJqdGkiOiI0NmI0MTA0NC03M2M2LTQ5MDEtOTcyMy0yZjE1NjE1ODgzZDgiLCJleHAiOjE1ODE0ODAzMjMsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODMiLCJhdWQiOiJNeVRlc3RBcGkifQ.EgVFlAzqOlV-RpjRRxXpQzp3q3kk1FqTcoaGDQBY0XA P>
D/OkHttp: “anyObjects”: “idGrupo”: “00d60025-6fb9-484f-97f0-08d79dfdbf92”, “文化之”: “”, “散列”: “BDZ5GA”, “标记”:“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfVXNlck5hbWUiOiJVU0VSX0JPTkFOWkExIiwiX0hhc2giOiJCRFo1R0EiLCJqdGkiOiI0NmI0MTA0NC03M2M2LTQ5MDEtOTcyMy0yZjE1NjE1ODgzZDgiLCJleHAiOjE1ODE0ODAzMjMsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODMiLCJhdWQiOiJNeVRlc3RBcGkifQ.EgVFlAzqOlV-RpjRRxXpQzp3q3kk1FqTcoaGDQBY0XA ","usuario":"USER_BONANZA1"
D/OkHttp: --> END POST (418-byte body)
D/OkHttp: http://192.168.1.68:83/api/Comercios/comercios (34 毫秒)
D/OkHttp:传输编码:分块
D/OkHttp: Content-Type: application/json;字符集=utf-8
D/OkHttp:服务器:Kestrel
D/OkHttp: X-Powered-By: ASP.NET
D/OkHttp:日期:2020 年 2 月 12 日,星期三,格林威治标准时间 01:05:45
它只是返回一个空的主体,没有其他解释原因。
在搜索socket closed error或者time out的时候,大多都是死胡同,说是和服务端有关,和应用无关,我和管理API和服务端的人聊了聊,时间和再一次有人告诉我,从他们这边看没有错,至少他们知道,他们提到的一件事是,可能正文的字节大小太大,这就是为什么不允许随机关闭套接字的原因,但我不知道如何保持打开状态,或者这是否是首要问题。
所以我想知道是否有办法查看有关 Okhttp 服务器的更详细日志,以便更好地搜索可能的解决方案。
我将在这里发布我的代码,我发送到 Web 服务的模型很好,这不是问题,因为如果结构不是服务器期望的那样,我会收到一个 onSuccess 响应,其中包含我的详细错误从服务器做错了,只是当一切正常时,我收到超时或套接字关闭,有时它工作有时它没有(根据邮递员和我的同行,不是服务器问题)但它永远不会工作当我在android模拟器上切换网络类型时,我已经在帖子中显示过。
这是我的 Gradle 实现
implementation "com.squareup.retrofit2:retrofit:2.5.0"
implementation "com.squareup.retrofit2:converter-gson:2.3.0"
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
这就是我构建客户端和改造的方式
private fun buildRetrofit(): Retrofit
val logger = HttpLoggingInterceptor()
logger.setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient()
.newBuilder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(FN.returnWebAPI(this))
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
这就是我拨打电话的方式,现在只是接收响应正文以确保它与数据解析无关。
val idGrupoComercios = hashMapOf("idGrupo" to id)
val hashComercio = HashComercio(hash, upperU.usuario.toUpperCase(Locale.getDefault()), "", jwt.toString(), idGrupoComercios
)
val callComercios: Call<ResponseBody> =
service.getComercios(tokenBearer, hashComercio)
callComercios.enqueue(object :
Callback<ResponseBody>
override fun onFailure(
call: Call<ResponseBody>,
t: Throwable
)
Crashlytics.logException(t)
override fun onResponse(
call: Call<ResponseBody>,
response: Response<ResponseBody>
)
if (response.code() == 200)
val data = response.body()!!
)
所以任何关于我能做什么的帮助或想法都会有很大的帮助,我现在似乎可以从项目的应用程序方面做一些事情,所以任何帮助都会很棒。
【问题讨论】:
可能使用pastebin.com 粘贴完整日志(删除了一些内容)并分享链接。理想情况下,完整的日志可以帮助某人查看正在发生的事情。 完整的 HtttpLoginterceptor 日志在我上面发布的 pastebin 上,pastebin.com/wRwnMrsk 但是如果您输入 Logcat 或 Java 控制台日志,这就是控制台没有给我更多信息的问题,至少使用方式它。日志只有两行 Socket Closed。 java.net.SocketException: Socket closed detail message: Socket closed that't it no more info ,这就是为什么我正在寻找一种获取更多信息的方法。 【参考方案1】:我们能够找到解决问题的方法。 过去,我尝试的最长超时时间是构建客户端时的 5 分钟,但是如果您不将其最大化,它构建的套接字似乎会关闭,因此我将超时更改为一天,这样它就会最大化可能需要超时。
Android 系统或服务器实际上不会等待一天的响应,因此,在大多数情况下,如果服务器没有重置连接,它会发送响应。
java.net.SocketException:连接重置
在这些情况下,您只需在 retryOnConnectionFailure 上设置 true,即使返回答案需要更多时间,它也会提供答案。
我与管理服务器的人交谈并告诉我问题是 HTTP 客户端或改造在第一次尝试时无法重建消息,如果响应正文太长,后续尝试更有可能失败使用 3g 连接,如果它在 json 中包含图像或哈希值,就像我正在做的那样 将完整图像的哈希放在 json 上。
这是客户端的代码
val client = OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.DAYS)
.readTimeout(1, TimeUnit.DAYS)
.writeTimeout(1, TimeUnit.DAYS)
.retryOnConnectionFailure(false)
.callTimeout(1, TimeUnit.DAYS)
.hostnameVerifier(HostnameVerifier hostname, session -> true )
.build()
他还告诉我,为了获得最佳结果,使用 HSDPA 时的 json 应小于 1024 字节,包括标头和所有内容。最多 2024 字节的响应正文。
【讨论】:
以上是关于如何查看 OkHttp 客户端的完整内部工作?改造插座关闭超时的主要内容,如果未能解决你的问题,请参考以下文章
改造 OkHttp SSLHandshakeException