Retrofit: Support http cache control stale-if-error and stale-while-revalidate

Created on 6 Apr 2016  路  4Comments  路  Source: square/retrofit

This two http headers are described in RFC5861

stale-while-revalidate
https://tools.ietf.org/html/rfc5861#section-3

stale-if-error
https://tools.ietf.org/html/rfc5861#section-4

OkHttp does NOT currently support them: https://github.com/square/okhttp/issues/1083

The reason is stated as "The catch is that implementing this will cause us to create two responses for a single request. We currently have no mechanism for that."
and the suggested workaround is to do 2 request passing CacheControl.FORCE_CACHE in the first one.

Retrofit build the request itself without exposing any way to set the cache control.
Retrofit also would have a way of providing 2 response when used with RxJava Observable.

Can you think of a way enabling users using RxJava to obtain this feature?

Blocked OkHttp

Most helpful comment

Like @1zaman said you can make two requests and merge the observables:

interface Service {
  @GET("some/url")
  @Headers("Cache-Control: only-if-cached")
  Observable<Whatever> someThingIfCached();

  @GET("some/url")
  @Headers("Cache-Control: no-cache")
  Observable<Whatever> someThingNetworkOnly();

  default Observable<Whatever> someThing() {
    return Observable.concat(
        someThingIfCached().onErrorResumeNext(Observable.empty()),
        someThingNetworkOnly()
    );
  }
}

All 4 comments

You can define the Cache-Control header in a Retrofit request method definition via the @Headers annotation. You can also use OkHttp interceptors to inject the header, possibly using multiple instances of OkHttpClient and Retrofit to build separate implementations of your API endpoints interface with the appropriate headers.

RxJava might also allow you to chain the two Observable instances. You could create a custom implementation of the requests interface that wraps around the two Retrofit ones and joins the two Observable for each method, either via manual definition, or automatically via Proxy. Unfortunately, it seems that you can't easily create a CallAdapter to do this, since Retrofit doesn't expose the OkHttp Call object or provide any other way to read or modify the headers from it's own Call interface.

Retrofit build the request itself without exposing any way to set the cache control.

You can use @Header or @Headers.

Retrofit also would have a way of providing 2 response when used with RxJava Observable.

The RxJava support only converts a Call into an Observable. It doesn't have the ability to make two different requests. Further complicating the problem, the implementation that converts Call to Observable uses the synchronous execution which blocks and returns the Response<T> object.

I don't really see any way forward with this until OkHttp goes to v4 and we provide a first-party mechanism for this in the HTTP client.

Like @1zaman said you can make two requests and merge the observables:

interface Service {
  @GET("some/url")
  @Headers("Cache-Control: only-if-cached")
  Observable<Whatever> someThingIfCached();

  @GET("some/url")
  @Headers("Cache-Control: no-cache")
  Observable<Whatever> someThingNetworkOnly();

  default Observable<Whatever> someThing() {
    return Observable.concat(
        someThingIfCached().onErrorResumeNext(Observable.empty()),
        someThingNetworkOnly()
    );
  }
}

Retrofit doesn't implement HTTP so OkHttp is the right layer for this.

Was this page helpful?
0 / 5 - 0 ratings