Comment utiliser l'intercepteur pour ajouter des en-têtes dans Retrofit 2.0?

96

Notre équipe décide d'adopter Retrofit 2.0 et je fais quelques recherches initiales à ce sujet. Je suis un débutant dans cette bibliothèque.

Je me demande comment utiliser interceptorpour ajouter des en-têtes personnalisés via Retrofits 2.0 dans notre application Android. Il existe de nombreux didacticiels sur l'utilisation interceptorpour ajouter des en-têtes dans Retrofit 1.X, mais comme les API ont beaucoup changé dans la dernière version, je ne sais pas comment adapter ces méthodes dans la nouvelle version. De plus, Retrofit n'a pas encore mis à jour sa nouvelle documentation.

Par exemple, dans les codes suivants, comment dois-je implémenter la Interceptorclasse pour ajouter des en-têtes supplémentaires? D'ailleurs, quel est exactement l' objet non documentéChain ? Quand sera-t- intercept()il appelé?

    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();
hackjutsu
la source
1
Assurez-vous que votre BASE_API_URL se termine par /et que vos URL d'API ne le font pas ( stuff/post/whatever)
EpicPandaForce

Réponses:

120

Regarde ça.

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()
        )        
    }
}
EpicPandaForce
la source
Merci!! Alors, cela intercept()se déclenche à chaque fois qu'une demande est envoyée depuis l'application? Pouvons-nous attraper la réponse intermédiaire pour la redirection ou obtenir simplement la réponse finale?
hackjutsu
Ceci est appelé pour chaque demande, et si je sais bien, c'est parce que vous l'ajoutez en tant qu'intercepteur, et non en tant qu'intercepteur de réseau. Je pense que vous ne pouvez obtenir que la réponse finale ici, mais il pourrait y avoir une configuration pour permettre de voir les redirections comme des redirections que je ne connais pas du haut de ma tête (il y en a aussi une pour la connexion URL http.)
EpicPandaForce
1
Reportez-vous simplement à ce lien: github.com/square/okhttp/wiki/Interceptors , et obtenez les informations dont j'ai besoin :) Merci ~
hackjutsu
5
Pour info, vous devez utiliser un constructeur au lieu de client.interceptors(). Cela ressemble ànew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee
22

Une autre alternative à la réponse acceptée

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;
    }
}
VenomVendor
la source
Agréable! Alors request.newBuilder().headers(moreHeaders).build()gardera les en-têtes d'origine?
hackjutsu
1
Oui. Aucun en-tête n'est supprimé de la demande sauf si removeAll (String name) est appelé.
VenomVendor
@VenomVendor s'il vous plaît aidez-moi avec une question similaire ici stackoverflow.com/questions/45078720/… merci
user606669
Cela ne va-t-il pas continuer à créer de nouveaux objets?
TheRealChx101
3
   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
la source
2

Vous pouvez utiliser des en-têtes avec des intercepteurs avec ses méthodes intégrées comme celle-ci

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

la source
Je veux savoir comment obtenez-vous le contexte à cet endroit?
rupinderjeet
@rupinderjeet Probablement un final Context contextdans la liste des paramètres.
TheRealChx101
@ TheRealChx101 Je voulais juste souligner que nous ne devrions pas avoir contextici parce que c'est de la logique métier.
rupinderjeet