OkHttp3套接字超时异常(在Android应用程序中)-- 如何为异步请求设置读取超时?

7
我在尝试使用OkHttp3异步Get时,经常遇到java.net.SocketTimeoutException异常。这表明我没有将读取超时值设置得足够高(我认为默认值为10秒)。
更大的问题是“如何防止出现此异常?”,但除非有更好的初始策略,否则我的直接问题是“如何为请求设置读取超时值?”。
在我的代码中,我使用了来自Okttp Recipes页面这里的信息。
请注意,try-catch的前两行被注释掉了。这是因为我无法使用所需的构建器(能够设置超时值的一个构建器,OkHttpClient.Builder)来添加标头信息(Request.Builder)。
我的代码如下:
    m_client = new OkHttpClient();


    try
    {
        //OkHttpClient.Builder bldr = m_client.newBuilder();
        //bldr.readTimeout(0, TimeUnit.SECONDS);

        Request.Builder reqBuilder = new Request.Builder();

        reqBuilder.addHeader("authorization", getToken());

        Request request = reqBuilder.url("http://plusdev.kooklah.com/api/v2_1/items/get").build();

        m_client.newCall(request).enqueue(new Callback()
        {
            @Override
            public void onFailure(Call call, IOException e)
            {
                Log.i("Logit", "Inside onFailure() -- IOException: " + e.getMessage() + " ----- stack trace: " + UtilGen.exceptionToString(e));

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                       // do stuff on UI thread
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response responseIn)
            {
                try
                {
                    m_sServerResponse = responseIn.body().string();
                }
                catch (Exception ex)
                {
                    Log.i("LogIt", "          ---Inside onResponse() -- Exception occurred. ex: " + ex.toString());
                }

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Log.i("LogIt", "          ---Inside onResponse() -- inside run().");
                        if (!m_sServerResponse.isEmpty())
                        {
                            Log.i("LogIt", "          ---Inside onResponse() -- inside run() -- Success");
                            processDownloadedAssessments(m_sServerResponse);
                        }
                    }
                });
            }
        });
    }
    catch (Exception ex)
    {
        Log.i("LogIt", "ex: " + ex.getMessage());
    }

我发现了一个似乎直接相关的问题,链接在okhttp的github网站上,这里。甚至有一个建议设置读取超时时间,正如上面提到的,已经被注释掉了,因为我无法弄清楚如何在描述的异步请求上使用那种构建器,该页面上的示例。我的异常堆栈跟踪如下,但请注意,大多数情况下我不会得到这个异常。堆栈跟踪:
01-19 14:04:52.192: I/LogIt(25650): Inside onFailure() -- IOException: null ----- stack trace: java.net.SocketTimeoutException
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
01-19 14:04:52.192: I/LogIt(25650):     at okio.Okio$2.read(Okio.java:138)
01-19 14:04:52.192: I/LogIt(25650):     at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponse(Http1Codec.java:191)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:132)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:54)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-19 14:04:52.192: I/LogIt(25650):     at java.lang.Thread.run(Thread.java:818)

OkHttpClient 构建器和 Request 构建器是两个不同的类。您可以在 OkHttpClient 构建器中设置超时时间,并将其应用于所有请求。您可以在 Request 构建器中为单个请求设置标头。 - LordRaydenMK
非常正确,但是在设置请求的超时值之后,如何将前者带入请求中呢? - Alyoshak
你可以使用设定了特定超时时间的构建器创建OkHttpClient对象,然后执行此Request - LordRaydenMK
@LordRaydenMK -- 正如问题中所提到的,async调用需要Request.Builder类,而不是OkHttpClient.Builder。 - Alyoshak
我在 Kotlin 中遇到了同样的问题。有人可以帮忙解决吗? - tinto mathew
1个回答

20

不是

m_client = new OkHttpClient();

你应该使用类似于构建器的方式创建客户端,例如:

m_client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build();

如果您像这样创建客户端,那么使用此客户端执行的每个Request(使用m_client.newCall(...))将使用构建器中指定的超时时间。


我知道你在干什么。得先关机一会儿,但尽快试试看。可能明天再联系。谢谢。 - Alyoshak
那就是我的问题,我没有在设置超时后对OkHttpClient builder使用build()调用。 - Alyoshak
2
当超时时,它们对应的异常是什么? - Beatrice Lin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接