En general, establecemos un tiempo de espera para el cliente okHttp y utilizamos una sola instancia de ese cliente. Por lo tanto, no podemos cambiar el tiempo de espera para ese cliente una vez que se genera.

¿Cómo cambiar el tiempo de espera para una solicitud en particular? Hay alguna manera hacerlo sin crear un nuevo cliente?

Es muy común que algunas llamadas tomen más tiempo al menos 1/2 por aplicación, lo que necesita más tiempo de espera que otras. sería genial si la solicitud puede anular el tiempo de espera predeterminado.

4
Ashok Varma 20 oct. 2017 a las 11:31

3 respuestas

La mejor respuesta

En 3.9 es posible configurar esto por solicitud en un 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());
      }
    };
  }
5
Yuri Schimke 20 mar. 2018 a las 07:01

Consulte https: // github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PerCallSettings.java que crea clones poco profundos que solo modifican algunas configuraciones.

// Copy to customize OkHttp for this request.
OkHttpClient client2 = client.newBuilder()
    .readTimeout(3000, TimeUnit.MILLISECONDS)
    .build();
6
Yuri Schimke 7 nov. 2017 a las 10:19

Actualizando a Retrofit 2.5.0 puede usar la clase Invocation

Nuevo: la clase de invocación proporciona una referencia al método invocado y la lista de argumentos como una etiqueta en la llamada OkHttp subyacente. Se puede acceder a esto desde un interceptor OkHttp para cosas como el registro, el análisis o la agregación de métricas.

De esa manera, puede crear una anotación SpecificTimeout para usar solo en las solicitudes que necesita para establecer una duración de tiempo de espera diferente y leer sus valores en un OkHttp Interceptor para cambiar el tiempo de espera en ese punto.

Anotación personalizada

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

Interfaz de servicio

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();
}

Interceptador

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();
9
4 revs, 2 users 98% 26 feb. 2020 a las 18:22