Jak użyć przechwytywacza, aby dodać nagłówki w Retrofit 2.0?

96

Nasz zespół zdecydował się na Retrofit 2.0 i przeprowadzam wstępne badania. Jestem nowicjuszem w tej bibliotece.

Zastanawiam się, jak interceptordodać niestandardowe nagłówki poprzez Retrofits 2.0 w naszej aplikacji na Androida. Istnieje wiele samouczków na temat interceptordodawania nagłówków w Retrofit 1.X, ale ponieważ interfejsy API bardzo się zmieniły w najnowszej wersji, nie jestem pewien, jak dostosować te metody w nowej wersji. Ponadto Retrofit nie zaktualizował jeszcze swojej nowej dokumentacji.

Na przykład w poniższych kodach, jak zaimplementować Interceptorklasę, aby dodać dodatkowe nagłówki? Poza tym, czym właściwie jest ten nieudokumentowany Chainobiekt ? Kiedy zostanie intercept()wezwany?

    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
źródło
1
Upewnij się, że Twój BASE_API_URL kończy się na, /a adresy URL Twojego interfejsu API nie ( stuff/post/whatever)
EpicPandaForce

Odpowiedzi:

120

Sprawdź to.

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
źródło
Dzięki!! Czy intercept()jest to wyzwalane za każdym razem, gdy żądanie jest wysyłane z aplikacji? Czy możemy przechwycić odpowiedź pośrednią na potrzeby przekierowania, czy po prostu uzyskać odpowiedź końcową?
hackjutsu
Jest to wywoływane przy każdym żądaniu i, jeśli wiem, to dlatego, że dodajesz go jako przechwytywacz, a nie jako przechwytywacz sieci. Myślę, że możesz uzyskać tutaj tylko ostateczną odpowiedź, ale może istnieć konfiguracja, która pozwoli widzieć przekierowania jako przekierowania, których nie znam od początku mojej głowy (jest też jedno dla połączenia z adresem URL http).
EpicPandaForce
1
Po prostu skorzystaj z tego linku: github.com/square/okhttp/wiki/Interceptors i uzyskaj informacje, których potrzebuję :) Dziękuję ~
hackjutsu
5
Fyi, zamiast tego musisz użyć kreatora client.interceptors(). To wygląda jaknew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee
22

Inna alternatywa dla zaakceptowanej odpowiedzi

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
źródło
Ładny! Czy więc request.newBuilder().headers(moreHeaders).build()zachowasz oryginalne nagłówki?
hackjutsu
1
Tak. Żadne nagłówki nie są usuwane z żądania, chyba że zostanie wywołane removeAll (nazwa ciągu) .
VenomVendor
@VenomVendor, pomóż mi z podobnym pytaniem tutaj stackoverflow.com/questions/45078720/… dzięki
user606669
Czy to nie będzie powodować tworzenia nowych obiektów?
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
źródło
2

Możesz używać nagłówków za pomocą Interceptorów z jego wbudowanymi metodami, takimi jak ta

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

źródło
Chcę wiedzieć, jak uzyskać kontekst w tym miejscu?
rupinderjeet
@rupinderjeet Prawdopodobnie final Context contextna liście parametrów.
TheRealChx101
@ TheRealChx101 Chciałem tylko zaznaczyć, że nie powinniśmy contexttutaj mieć , ponieważ jest to logika biznesowa.
rupinderjeet