Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consuming One-Shot ResponseBody from Okhttp causes issues with Retrofit

I am using an Retrofit with an Okhttp interceptor in order to detect if my oauth token has expired. If the token has expired, I want to request a new token, try the request again, then send that response to Retrofit.

Here is my interceptor class:

public class CustomInterceptor implements Interceptor {

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

    // try the request
    Response response = chain.proceed(request);

    if (response.body().string().contains(Constants.TOKEN_AUTH_ERROR_MESSAGE)) {
        Log.v("retrofit_error", "token expired");

        //get current token, create headers
        OAuthTokenResponse expiredToken = SharedPreferencesUtil.getOAuthToken();

        OAuthTokenResponse newOauthToken = RestClient.getInstance().getTokenService().refreshOauthToken(expiredToken.getRefreshToken());

        //store new token, return
        SharedPreferencesUtil.saveOAuthToken(newOauthToken);

        // create a new request and modify it accordingly using the new token
        Request.Builder newRequestBuilder = request.newBuilder()
                .removeHeader("Authorization");

        Request newRequest = newRequestBuilder.addHeader("Authorization", SharedPreferencesUtil.getOAuthToken().getAccessToken()).build();
        // retry the request
        return chain.proceed(newRequest);
    }

    // otherwise just pass the original response on
    return response;
}

}

The issue is that calling response.body.string() will consume the ResponseBody due to it being a one-shot value as the Okhttp docs state.

This means that the Response returned at the end of the code will no longer container the body when it is passed off to retrofit. Is there any way that I can consume the body while still returning it with the response?

Thanks!

like image 805
tylerjroach Avatar asked Feb 03 '15 18:02

tylerjroach


2 Answers

I accomplished this by creating a new response using the Response.Builder. I am able to use responseBodyString for my checks; then I return newResponse, which is given the body that I consumed.

Request request = chain.request();
Response response = chain.proceed(request);

ResponseBody responseBody = response.body();
String responseBodyString = response.body().string();
Response newResponse = response.newBuilder().body(ResponseBody.create(responseBody.contentType(), responseBodyString.getBytes())).build();

...

return newResponse;
like image 76
theblang Avatar answered Sep 21 '22 22:09

theblang


you can use Logging Interceptor https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor

like image 40
Sam Avatar answered Sep 23 '22 22:09

Sam