Wie verwende ich Interceptor, um Header in Retrofit 2.0 hinzuzufügen?

94

Unser Team hat sich für Retrofit 2.0 entschieden und ich mache einige erste Untersuchungen dazu. Ich bin ein Neuling in dieser Bibliothek.

Ich frage mich, wie ich interceptorbenutzerdefinierte Header über Retrofits 2.0 in unserer Android-App hinzufügen kann . Es gibt viele Tutorials über die Verwendung von interceptorHeader in Retrofit 1.x hinzufügen, aber da die APIs viel in der letzten Version geändert haben, ich bin nicht sicher , wie diese Methoden in der neuen Version anzupassen. Außerdem hat Retrofit seine neue Dokumentation noch nicht aktualisiert.

Wie soll ich beispielsweise in den folgenden Codes die InterceptorKlasse implementieren , um zusätzliche Header hinzuzufügen? Was genau ist das undokumentierte ChainObjekt ? Wann wird der intercept()angerufen?

    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
quelle
1
Stellen Sie sicher, dass Ihre BASE_API_URL mit endet /und dass Ihre API-URLs nicht ( stuff/post/whatever)
EpicPandaForce

Antworten:

118

Überprüfen Sie dies heraus.

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
quelle
Vielen Dank!! Dies intercept()wird also jedes Mal ausgelöst, wenn eine Anfrage von der Anwendung gesendet wird? Können wir die Zwischenantwort für die Umleitung abfangen oder erhalten wir nur die endgültige Antwort?
Hackjutsu
Dies wird für jede Anforderung aufgerufen, und wenn ich es richtig weiß, liegt es daran, dass Sie es als Interceptor und nicht als Netzwerk-Interceptor hinzufügen. Ich denke, Sie können hier nur die endgültige Antwort erhalten, aber es gibt möglicherweise eine Konfiguration, mit der Weiterleitungen als Weiterleitungen
angezeigt werden können
1
Beziehen
5
Zu Ihrer Information, Sie müssen stattdessen einen Builder verwenden client.interceptors(). Das sieht aus wienew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee
22

Eine weitere Alternative zur akzeptierten Antwort

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
quelle
Nett! So request.newBuilder().headers(moreHeaders).build()werden die ursprünglichen Header behalten?
Hackjutsu
1
Ja. Es werden keine Header aus der Anforderung entfernt, es sei denn, removeAll (String name) wird aufgerufen.
VenomVendor
@VenomVendor bitte helfen Sie mir mit einer ähnlichen Frage hier stackoverflow.com/questions/45078720/… danke
user606669
Wird dies nicht immer neue Objekte erstellen?
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
quelle
2

Sie können Header mit Interceptors mit den darin integrierten Methoden verwenden

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

quelle
Ich möchte wissen, wie Sie an diesem Ort Kontext bekommen ?
Rupinderjeet
@ Rupinderjeet Wahrscheinlich ein final Context contextin der Liste der Parameter.
TheRealChx101
@ TheRealChx101 Ich wollte nur darauf hinweisen, dass wir hier nicht haben sollten context, weil dies Geschäftslogik ist.
Rupinderjeet