121

Our team decide to adopt Retrofit 2.0 and I'm doing some initial research on it. I'm a newbie to this library.

I'm wondering how to use interceptor to add customized headers via Retrofits 2.0 in our Android app. There are many tutorials about using interceptor to add headers in Retrofit 1.X, but since the APIs have changed a lot in the latest version, I'm not sure how to adapt those methods in the new version. Also, Retrofit hasn't update its new documentation yet.

For example, in the following codes, how should I implement the Interceptor class to add extra headers? Besides, what exactly is the undocumented Chain object? When will the intercept() be called?

    OkHttpClient client = new OkHttpClient();
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());

            // How to add extra headers?

            return response;
        }
    });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_API_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
halfer
  • 19,824
  • 17
  • 99
  • 186
hackjutsu
  • 8,336
  • 13
  • 47
  • 87

4 Answers4

152

Check this out.

public class HeaderInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request()
                .newBuilder()
                .addHeader("appid", "hello")
                .addHeader("deviceplatform", "android")
                .removeHeader("User-Agent")
                .addHeader("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0")
                .build();
        Response response = chain.proceed(request);
        return response;
    }
}

Kotlin

class HeaderInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response = chain.run {
        proceed(
            request()
                .newBuilder()
                .addHeader("appid", "hello")
                .addHeader("deviceplatform", "android")
                .removeHeader("User-Agent")
                .addHeader("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0")
                .build()
        )        
    }
}
æ-ra-code
  • 2,140
  • 30
  • 28
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • Thanks!! So, this `intercept()` is triggered every time a request is sent from the application? Can we catch the intermediate response for redirect, or we just get the final response? – hackjutsu Oct 06 '15 at 17:11
  • This is called for every request, and if I know right, it is because you add it as an interceptor, and not as a network interceptor. I think you can get only the final response here, but there might be a config to allow seeing redirects as redirects that I don't know off the top of my head (there is one for http URL connection too.) – EpicPandaForce Oct 06 '15 at 17:22
  • 1
    Just refer to this link: https://github.com/square/okhttp/wiki/Interceptors , and get the information I need:) Thank you~ – hackjutsu Oct 06 '15 at 18:32
  • 5
    Fyi, you need to use a builder instead of `client.interceptors()`. This looks like `new OkHttpClient.Builder().addInterceptor().build()` – GLee Aug 16 '16 at 16:01
26

Another alternative from the accepted answer

public class HeaderInterceptor implements Interceptor {

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

        request = request.newBuilder()
                .addHeader("headerKey0", "HeaderVal0")
                .addHeader("headerKey0", "HeaderVal0--NotReplaced/NorUpdated") //new header added
                .build();

        //alternative
        Headers moreHeaders = request.headers().newBuilder()
                .add("headerKey1", "HeaderVal1")
                .add("headerKey2", "HeaderVal2")
                .set("headerKey2", "HeaderVal2--UpdatedHere") // existing header UPDATED if available, else added.
                .add("headerKey3", "HeaderKey3")
                .add("headerLine4 : headerLine4Val") //line with `:`, spaces doesn't matter.
                .removeAll("headerKey3") //Oops, remove this.
                .build();

        request = request.newBuilder().headers(moreHeaders).build();

        /* ##### List of headers ##### */
        // headerKey0: HeaderVal0
        // headerKey0: HeaderVal0--NotReplaced/NorUpdated
        // headerKey1: HeaderVal1
        // headerKey2: HeaderVal2--UpdatedHere
        // headerLine4: headerLine4Val

        Response response = chain.proceed(request);
        return response;
    }
}
Community
  • 1
  • 1
VenomVendor
  • 15,064
  • 13
  • 65
  • 96
4
   public class ServiceFactory {  
    public static ApiClient createService(String authToken, String userName, String password) {
            OkHttpClient defaultHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(
                            chain -> {
                                Request request = chain.request().newBuilder()
                                        .headers(getJsonHeader(authToken))
                                        .build();
                                return chain.proceed(request);
                            })
                    .authenticator(getBasicAuthenticator(userName, password))
                    .build();
            return getService(defaultHttpClient);
        }
        private static Headers getJsonHeader(String authToken) {
            Headers.Builder builder = new Headers.Builder();
            builder.add("Content-Type", "application/json");
            builder.add("Accept", "application/json");
            if (authToken != null && !authToken.isEmpty()) {
                builder.add("X-MY-Auth", authToken);
            }
            return builder.build();
        }
        private static Authenticator getBasicAuthenticator(final String userName, final String password) {
            return (route, response) -> {
                String credential = Credentials.basic(userName, password);
                return response.request().newBuilder().header("Authorization", credential).build();
            };
        }
          private static ApiClient getService(OkHttpClient defaultHttpClient) {
            return new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .client(defaultHttpClient)
                    .build()
                    .create(ApiClient.class);
        }
}
Fawad Badar
  • 436
  • 5
  • 7
3

You can headers using Interceptors with its built-in methods like this

   interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();

            Request.Builder builder = original.newBuilder();

            builder.header("Authorization","Bearer "+ LeafPreference.getInstance(context).getString(LeafPreference.TOKEN));

            Request request = builder.method(original.method(), original.body())
                    .build();
            Log.e("request",request.urlString());
            Log.e("header",request.header("Authorization"));
            return chain.proceed(request);
        }
    });
}
  • I want to know how do you get *context* at this place? – rupinderjeet Apr 06 '19 at 06:22
  • @rupinderjeet Probably a `final Context context` in the list of parameters. – TheRealChx101 Jul 12 '19 at 17:46
  • @TheRealChx101 Just wanted to point out that we shouldn't have `context` here because this is business logic. – rupinderjeet Jul 16 '19 at 10:33
  • @rupinderjeet You can have application context here if you want (`context.applicationContext`). – Mohit Atray Jul 18 '21 at 13:37
  • @MohitAtray Yes, maybe. These days, I have a habit of completely separating all network logic in a different module. This network module is independent of android dependencies. That's why I was being skeptical about using `context` directly here. – rupinderjeet Jul 20 '21 at 06:11