Как использовать перехватчик для добавления заголовков в Retrofit 2.0?

96

Наша команда решила внедрить Retrofit 2.0, и я провожу предварительные исследования. Я новичок в этой библиотеке.

Мне интересно, как использовать interceptorдля добавления настраиваемых заголовков через Retrofits 2.0 в нашем приложении для Android. Существует множество руководств по использованию interceptorдля добавления заголовков в Retrofit 1.X, но поскольку API-интерфейсы сильно изменились в последней версии, я не уверен, как адаптировать эти методы в новой версии. Кроме того, Retrofit еще не обновил свою новую документацию.

Например, в следующих кодах, как мне реализовать Interceptorкласс для добавления дополнительных заголовков? Кроме того, что такое недокументированный Chainобъект ? Когда будет intercept()называться?

    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
Убедитесь, что ваш BASE_API_URL заканчивается на /и что ваши URL-адреса API не имеют ( stuff/post/whatever)
EpicPandaForce

Ответы:

120

Проверь это.

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

Котлин

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
источник
Спасибо!! Итак, это intercept()срабатывает каждый раз, когда из приложения отправляется запрос? Можем ли мы поймать промежуточный ответ для перенаправления или просто получить окончательный ответ?
hackjutsu 06
Это вызывается для каждого запроса, и, если я правильно знаю, это потому, что вы добавляете его как перехватчик, а не как сетевой перехватчик. Я думаю, вы можете получить здесь только окончательный ответ, но может быть конфигурация, позволяющая видеть перенаправления как перенаправления, о которых я не знаю, что я не знаю (есть еще один для соединения URL-адреса http.)
EpicPandaForce,
1
Просто перейдите по этой ссылке: github.com/square/okhttp/wiki/Interceptors , и получите необходимую мне информацию :) Спасибо ~
hackjutsu
5
Fyi, вам нужно использовать строитель вместо client.interceptors(). Это выглядит такnew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee
22

Еще одна альтернатива из принятого ответа

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
источник
Ницца! Так request.newBuilder().headers(moreHeaders).build()что сохраним исходные заголовки?
hackjutsu
1
Да. Заголовки не удаляются из запроса, если не вызывается removeAll (String name) .
VenomVendor
@VenomVendor, пожалуйста, помогите мне с аналогичным вопросом здесь stackoverflow.com/questions/45078720/… спасибо
user606669
Разве это не будет создавать новые объекты?
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

Вы можете использовать заголовки с помощью перехватчиков с помощью встроенных методов, подобных этому

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

источник
Я хочу знать, как вы понимаете контекст в этом месте?
rupinderjeet
@rupinderjeet Вероятно, final Context contextв списке параметров.
TheRealChx101
@ TheRealChx101 Просто хотел указать, что здесь не должно быть, contextпотому что это бизнес-логика.
rupinderjeet