¿Cómo usar el interceptor para agregar encabezados en Retrofit 2.0?


95

Nuestro equipo decide adoptar Retrofit 2.0 y estoy haciendo una investigación inicial al respecto. Soy un novato en esta biblioteca.

Me pregunto cómo usar interceptorpara agregar encabezados personalizados a través de Retrofits 2.0 en nuestra aplicación de Android. Hay muchos tutoriales sobre el uso interceptorpara agregar encabezados en Retrofit 1.X, pero dado que las API han cambiado mucho en la última versión, no estoy seguro de cómo adaptar esos métodos en la nueva versión. Además, Retrofit aún no ha actualizado su nueva documentación.

Por ejemplo, en los siguientes códigos, ¿cómo debo implementar la Interceptorclase para agregar encabezados adicionales? Además, ¿qué es exactamente el objeto indocumentadoChain ? ¿Cuándo se intercept()llamará?

    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
Asegúrese de que su BASE_API_URL termine con /y que sus URL de API no ( stuff/post/whatever)
EpicPandaForce

Respuestas:


119

Mira esto.

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

¡¡Gracias!! Entonces, ¿esto intercept()se activa cada vez que se envía una solicitud desde la aplicación? ¿Podemos captar la respuesta intermedia para la redirección o simplemente obtenemos la respuesta final?
hackjutsu

Esto se solicita para cada solicitud, y si lo sé bien, es porque lo agrega como un interceptor y no como un interceptor de red. Creo que solo puede obtener la respuesta final aquí, pero puede haber una configuración para permitir ver las redirecciones como redirecciones que no conozco de la parte superior de mi cabeza (también hay una para la conexión de URL http)
EpicPandaForce

1
Simplemente consulte este enlace: github.com/square/okhttp/wiki/Interceptors y obtenga la información que necesito :) Gracias ~
hackjutsu

5
Para tu información, necesitas usar un constructor en lugar de client.interceptors(). Esto parecenew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee

22

Otra alternativa de la respuesta aceptada.

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

¡Agradable! Entonces, request.newBuilder().headers(moreHeaders).build()¿mantendrá los encabezados originales?
hackjutsu

1
Si. No se eliminan encabezados de la solicitud a menos que se llame a removeAll (nombre de cadena) .
VenomVendor

@VenomVendor, por favor ayúdenme con una pregunta similar aquí stackoverflow.com/questions/45078720/… gracias
user606669

¿No seguirá esto creando nuevos objetos?
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

Puede encabezados usando Interceptores con sus métodos integrados como este

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

Quiero saber cómo se obtiene contexto en este lugar.
rupinderjeet

@rupinderjeet Probablemente esté final Context contexten la lista de parámetros.
TheRealChx101

@ TheRealChx101 Solo quería señalar que no deberíamos estar contextaquí porque esto es lógica empresarial.
rupinderjeet
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.