52

I've been trying to implement an interceptor ( OkHttp 3.2 & Retrofit 2 ) for editing the JSON response before is returned as response. The server we request data returns different data dependes on success or error and that makes difficult to map the objects.

I was trying to do it by adding the interceptor to Retrofit as a NetworkInterceptor, however the string returned had no format.

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

        Response response = chain.proceed(request);
        try {

            final String responseString = new String(response.body().bytes() ); 

            LOGD("OkHttp-NET-Interceptor", "Response: " + responseString);

            String  newResponseString = editResponse( responseString );

            LOGD("OkHttp-NET-Interceptor", "Response edited: " + newResponseString);
            return  response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), newResponseString))
                    .build();

        }catch (Exception ex){
            return response;
        }
    }

responseString had a string without any understandable format.

After changing to the normal interceptor, the string had format a it was able to convert to JSONObject.

Could tell me someone which are the differences between the responses?

why this line new String(response.body().bytes() ); return different content?

Vinh Nguyen
  • 610
  • 7
  • 16
Jose M Lechon
  • 5,766
  • 6
  • 44
  • 60

2 Answers2

94

The differences are in the names. NetworkInterceptor hooks in at the network level and is an ideal place to put retry logic and anything that doesn't rely on the actual content of the response.

If what you do depends on the contents of the response (like in your case), using a ApplicationInterceptor is more useful, as it gives you the response after it's been processed by any other moving parts you may have such as a JSON deserializer. Otherwise you would have to implement the JSON deserializing yourself inside the NetworkInterceptor which doesn't make much sense considering it's done for you by Retrofit.

Clarification

Square have this useful diagram on their wiki that shows where each type of interceptor sits

interceptor diagram

Thus, the reason you receive a readable string in the ApplicationInterceptor is because Square are trying to de-couple the purposes of the two interceptor types. They don't think you should be making any application dependent decisions in the NetworkInterceptor, and so they don't provide an easy way for you to access the response string. It is possible to get ahold of, but like I said, they don't want you to make decisions that depend on the content of the response - rather, they want you to make decisions based or the network state, or headers etc.

The ApplicationInterceptor is where they want you to make decisions dependent upon the contents of the response, so they provide easier methods to access the content of the response so that you can make informed decisions to retry, or as they detail in their wiki, rewrite responses (which I believe is what you're trying to do).

roarster
  • 4,058
  • 2
  • 25
  • 38
  • 1
    Thanks for your explanation, it gives me de idea about what does each interceptor. However, why the NetworkInterceptor does not return a readable String and the normal interceptor does ? – Jose M Lechon May 10 '16 at 07:42
  • @Lechon I've added more to my answer to try to explain some more – roarster May 10 '16 at 09:35
  • The source of this diagram, along with more documentation, is here: https://square.github.io/okhttp/interceptors/ – yuval Apr 30 '21 at 19:35
2

According to @square:

Each interceptor chain has relative merits.

Application interceptors

  • Don’t need to worry about intermediate responses like redirects and retries.

  • Are always invoked once, even if the HTTP response is served from the cache.

  • Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match.

  • Permitted to short-circuit and not call Chain.proceed().

  • Permitted to retry and make multiple calls to Chain.proceed().

  • Can adjust Call timeouts using withConnectTimeout, withReadTimeout, withWriteTimeout.

Network Interceptors

  • Able to operate on intermediate responses like redirects and retries.
  • Not invoked for cached responses that short-circuit the network.
  • Observe the data just as it will be transmitted over the network.
  • Access to the Connection that carries the request.
Simon
  • 2,643
  • 3
  • 40
  • 61