Bagaimana cara menggunakan pencegat untuk menambahkan Header di Retrofit 2.0?


96

Tim kami memutuskan untuk mengadopsi Retrofit 2.0 dan saya sedang melakukan penelitian awal untuk itu. Saya pemula di perpustakaan ini.

Saya bertanya-tanya bagaimana cara interceptormenambahkan header yang disesuaikan melalui Retrofits 2.0 di aplikasi Android kami. Ada banyak tutorial tentang penggunaan interceptoruntuk menambahkan tajuk di Retrofit 1.X, tetapi karena API telah banyak berubah di versi terbaru, saya tidak yakin bagaimana mengadaptasi metode tersebut di versi baru. Juga, Retrofit belum memperbarui dokumentasi barunya.

Misalnya, dalam kode berikut, bagaimana cara mengimplementasikan Interceptorkelas untuk menambahkan header tambahan? Selain itu, apa sebenarnya obyek yang tidak berdokumen Chainitu ? Kapan intercept()dipanggil?

    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
Pastikan BASE_API_URL Anda diakhiri dengan /dan URL API Anda tidak ( stuff/post/whatever)
EpicPandaForce

Jawaban:


120

Lihat ini.

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

Terima kasih!! Jadi, ini intercept()dipicu setiap kali permintaan dikirim dari aplikasi? Bisakah kita menangkap respons perantara untuk pengalihan, atau kita hanya mendapatkan respons akhir?
hackjutsu

Ini dipanggil untuk setiap permintaan, dan jika saya tahu benar, itu karena Anda menambahkannya sebagai penyergap, dan bukan sebagai penyergap jaringan. Saya pikir Anda hanya bisa mendapatkan tanggapan akhir di sini, tetapi mungkin ada konfigurasi untuk memungkinkan melihat pengalihan sebagai pengalihan yang saya tidak tahu di luar kepala saya (ada satu untuk koneksi URL http juga.)
EpicPandaForce

1
Lihat saja tautan ini: github.com/square/okhttp/wiki/Interceptors , dan dapatkan informasi yang saya butuhkan :) Terima kasih ~
hackjutsu

5
Untuk diketahui, Anda perlu menggunakan builder, bukan client.interceptors(). Ini terlihat sepertinew OkHttpClient.Builder().addInterceptor(<Your Interceptor>).build()
GLee

22

Alternatif lain dari jawaban yang diterima

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

Bagus! Jadi request.newBuilder().headers(moreHeaders).build()akan mempertahankan header asli?
hackjutsu

1
Iya. Tidak ada header yang dihapus dari permintaan kecuali removeAll (nama String) dipanggil.
VenomVendor

@VenomVendor tolong bantu saya dengan pertanyaan serupa di sini stackoverflow.com/questions/45078720/… terima kasih
user606669

Bukankah ini akan terus menciptakan objek baru?
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

Anda dapat membuat header menggunakan Interceptors dengan metode bawaannya seperti ini

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

Saya ingin tahu bagaimana Anda mendapatkan konteks di tempat ini?
rupinderjeet

@rupinderjeet Mungkin ada final Context contextdalam daftar parameter.
TheRealChx101

@ TheRealChx101 Hanya ingin menunjukkan bahwa kita tidak boleh melakukannya di contextsini karena ini adalah logika bisnis.
rupinderjeet
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.