Come utilizzare l'interceptor per aggiungere intestazioni in Retrofit 2.0?


96

Il nostro team decide di adottare Retrofit 2.0 e sto facendo alcune ricerche iniziali su di esso. Sono un principiante in questa libreria.

Mi chiedo come utilizzare interceptorper aggiungere intestazioni personalizzate tramite Retrofits 2.0 nella nostra app Android. Esistono molti tutorial sull'uso interceptorper aggiungere intestazioni in Retrofit 1.X, ma poiché le API sono cambiate molto nell'ultima versione, non sono sicuro di come adattare questi metodi nella nuova versione. Inoltre, Retrofit non ha ancora aggiornato la sua nuova documentazione.

Ad esempio, nei seguenti codici, come devo implementare la Interceptorclasse per aggiungere intestazioni extra? Inoltre, cos'è esattamente l' oggetto non documentatoChain ? Quando verrà intercept()chiamato?

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

1
Assicurati che il tuo BASE_API_URL termini con /e che i tuoi URL API non ( stuff/post/whatever)
EpicPandaForce

Risposte:


120

Controllalo.

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

Grazie!! Quindi, questo intercept()viene attivato ogni volta che viene inviata una richiesta dall'applicazione? Possiamo catturare la risposta intermedia per il reindirizzamento o semplicemente ottenere la risposta finale?
hackjutsu

Questo viene chiamato per ogni richiesta e, se so bene, è perché lo aggiungi come intercettore e non come intercettore di rete. Penso che tu possa ottenere solo la risposta finale qui, ma potrebbe esserci una configurazione per consentire di vedere i reindirizzamenti come reindirizzamenti che non conosco dalla parte superiore della mia testa (ce n'è uno anche per la connessione URL http.)
EpicPandaForce

1
Basta fare riferimento a questo link: github.com/square/okhttp/wiki/Interceptors e ottenere le informazioni di cui ho bisogno :) Grazie ~
hackjutsu

5
Cordiali saluti, devi usare un builder invece di client.interceptors(). Questo sembranew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee

22

Un'altra alternativa dalla risposta accettata

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

Bello! Quindi request.newBuilder().headers(moreHeaders).build()manterrà le intestazioni originali?
hackjutsu

1
Sì. Nessuna intestazione viene rimossa dalla richiesta a meno che non venga chiamato removeAll (nome stringa) .
VenomVendor

@VenomVendor Please help me con una domanda simile qui stackoverflow.com/questions/45078720/... grazie
user606669

Questo non continuerà a creare nuovi oggetti?
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);
        }
}

2

Puoi intestare usando Interceptors con i suoi metodi integrati come questo

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

Voglio sapere come ottieni il contesto in questo posto?
rupinderjeet

@rupinderjeet Probabilmente un final Context contextnell'elenco dei parametri.
TheRealChx101

@ TheRealChx101 Volevo solo sottolineare che non dovremmo avere contextqui perché questa è la logica aziendale.
rupinderjeet
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.