发布大型正文时,okHttp 总是超时
Posted
技术标签:
【中文标题】发布大型正文时,okHttp 总是超时【英文标题】:okHttp always timeout when POST a large body 【发布时间】:2021-10-16 08:08:47 【问题描述】:我使用 okHttp 做一个 POST 请求,当字段 String.length 小于 500 左右时它可以工作。
这样的代码,okHttp的常规使用方式:
Request.Builder builder = new Request.Builder();
builder.url(getHostname() + getUrl());
builder.post(new FormBody.Builder.add("key", "the large string").build())
Call call = mOkHttpClient.newCall(builder.build());
call.enqueue(new Callback()
@Override
public void onFailure(Call call, IOException e)
e.printStackTrace();
@Override
public void onResponse(Call call, Response response) throws IOException
String output = response.body().string();
Log.d("okHttp response", output);
);
但是当这个参数字段长度 > 500,比如 1k,不确定确切的值时,它会抛出 java.net.SocketTimeoutException: timeout:
java.net.SocketTimeoutException: timeout
at okio.SocketAsyncTimeout.newTimeoutException(JvmOkio.kt:143)
at okio.AsyncTimeout.access$newTimeoutException(AsyncTimeout.kt:162)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:335)
at okio.RealBufferedSource.indexOf(RealBufferedSource.kt:427)
at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:320)
at okhttp3.internal.http1.HeadersReader.readLine(HeadersReader.kt:29)
at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.kt:178)
at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:106)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(SocketInputStream.java:203)
at java.net.SocketInputStream.read(SocketInputStream.java:139)
at okio.InputStreamSource.read(JvmOkio.kt:90)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
... 20 more
我是否设置超时:
int TIMEOUT = 60;
mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT,TimeUnit.SECONDS)
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.build();
它总是在我设置的 TIMEOUT 之后抛出 SocketTimeoutException。就好像它甚至不发送数据只是等待超时。
我试过了:
1.扩展的TIMEOUT设置值,但它只是保持发布并抛出timeoutException直到时间结束。
2.在postman中测试使用同样的大数据,上传耗时1s。字段长度不算长,8k左右。
3.现在将okhttp版本从3.12.0更新到最新的4.9.1。
但没有解决这个问题。
我继续测试程序,发现了一些新的东西:
此问题仅出现在 android Pad 上。当我用我的手机测试时,相同的数据不会超时。
1.我在华为 P30 pro(android 10) 上测试过,它可以在三星 Galaxy Tab active pro(android11) 和小米 PAD4(android8.1) 上运行,我不确定这是否只发生在 pad 上,或者这只是一个巧合。
2.我用我的三星平板进行了测试,并与 Charles 建立了代理。当我使用代理访问网络并想要捕获内容数据时,该程序可以正常工作。如果代理被取消,问题又出现了。
【问题讨论】:
记录getHostname() + getUrl()
并查看完整的url。你在邮递员中使用的体型是什么?
url 是对的,POSTMAN 使用 form-data 或 x-www-form-urlencoded 都可以。当“key”字段长度小于500时代码可以在1s内得到响应,但是当字段长度刚刚增加到750时继续发送,无论我如何扩展超时设置,它只是继续发送utils时间结束。
是本地服务器吗?
不是本地服务器,因为它是远程服务器。我可以在 android 上的 post 参数长度小于 500 字节时得到响应,也可以通过 postman 得到响应,无论参数长度有多长。当我在 android 上更改此参数的长度时无法响应。这是唯一的区别。
也许可以针对httpbin.org/post 之类的测试站点进行测试,看看这是一般问题,还是您的服务器正在做的事情。
【参考方案1】:
问题已解决。是网络配置问题。经过一些对比测试,我尝试了热点,或者蜂窝网络,或者换了另一个WiFi。这个 POST API 可以成功。奇怪的是,在同一个WiFi下,手机和PAD还是有区别的。不过还是不知道是路由器的wifi配置的问题还是pad的wifi配置的问题。
【讨论】:
以上是关于发布大型正文时,okHttp 总是超时的主要内容,如果未能解决你的问题,请参考以下文章
使用Retrofit(Okhttp)时如何从android studio中的log cat复制请求正文,标头(不带标签)?