How to change timeout for a request in okhttp

巧了我就是萌 提交于 2021-02-18 11:00:28

问题


In general we set timeout for the okHttp client and we use single instance of that client. So, we can't change the timeout for that client once it's generated.

How to change the timeout for a particular request ?? Is there anyway to do it without creating new client??

It's very common that some calls take more time atleast 1/2 per app, which needs more timeout than others. it would be great if request can override the default timeout.


回答1:


In 3.9 it is possible to set this per request in an interceptor

https://github.com/square/okhttp/blob/36bd68aa3e93affb12504cd40454e64c6812019c/okhttp-tests/src/test/java/okhttp3/InterceptorTest.java#L747-L757

  @Test public void chainWithReadTimeout() throws Exception {
    Interceptor interceptor1 = new Interceptor() {
      @Override public Response intercept(Chain chainA) throws IOException {
        assertEquals(5000, chainA.readTimeoutMillis());

        Chain chainB = chainA.withReadTimeout(100, TimeUnit.MILLISECONDS);
        assertEquals(100, chainB.readTimeoutMillis());

        return chainB.proceed(chainA.request());
      }
    };
  }



回答2:


Updating to Retrofit 2.5.0 you can use Invocation class

New: Invocation class provides a reference to the invoked method and argument list as a tag on the underlying OkHttp Call. This can be accessed from an OkHttp interceptor for things like logging, analytics, or metrics aggregation.

In that way, you can create a SpecificTimeout annotation to be used only on the requests you need to set a different timeout duration and read its values on an OkHttp Interceptor to change the timeout at that point.

Custom Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SpecificTimeout {
    int duration();
    TimeUnit unit();
}

Service Interface

public interface GitHubService {
    @GET("/users")
    @SpecificTimeout(duration = 5000, unit = TimeUnit.MILLISECONDS)
    Call<List<User>> listUsers();

    @GET("/repos")
    @SpecificTimeout(duration = 15000, unit = TimeUnit.MILLISECONDS)
    Call<List<Repo>> listRepos();
}

Interceptor

class TimeoutInterceptor implements Interceptor {

    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        Request request = chain.request();

        final Invocation tag = request.tag(Invocation.class);
        final Method method = tag != null ? tag.method() : null;
        final SpecificTimeout timeout = method != null ? method.getAnnotation(SpecificTimeout.class) : null;

        if (timeout != null) {
           return chain.withReadTimeout(timeout.duration(), timeout.unit())
                       .withConnectTimeout(timeout.duration(), timeout.unit())
                       .withWriteTimeout(timeout.duration(), timeout.unit())
                       .proceed(request);
        }

        return chain.proceed(request);
    }
}

OkHttp Builder

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //default timeout for not annotated requests
                .readTimeout(10000, TimeUnit.MILLISECONDS)
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .writeTimeout(10000, TimeUnit.MILLISECONDS)
                .addInterceptor(new TimeoutInterceptor())
                .build();



回答3:


See https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PerCallSettings.java which creates shallow clones that only modify some settings.

// Copy to customize OkHttp for this request.
OkHttpClient client2 = client.newBuilder()
    .readTimeout(3000, TimeUnit.MILLISECONDS)
    .build();



回答4:


I think a good way is to read a custom header on an interceptor and change the current timeout to calls that contains this specific header, it's works better than create a annotation and use reflection to read it. E.G:

class TimeoutInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        return request.header("Custom-Timeout")?.let {
            val newTimeout = it.toInt()
            chain.withReadTimeout(newTimeout, TimeUnit.MILLISECONDS)
                .withConnectTimeout(newTimeout, TimeUnit.MILLISECONDS)
                .withWriteTimeout(newTimeout, TimeUnit.MILLISECONDS)
                .proceed(request)
        } ?: chain.proceed(request)
    }
}


来源:https://stackoverflow.com/questions/46845206/how-to-change-timeout-for-a-request-in-okhttp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!