จะใช้ interceptor เพื่อเพิ่ม Headers ใน 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;
    }
}

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

ขอบคุณ !! ดังนั้นสิ่งนี้intercept()จะเกิดขึ้นทุกครั้งที่มีการส่งคำขอจากแอปพลิเคชัน? เราสามารถตรวจจับการตอบสนองระดับกลางสำหรับการเปลี่ยนเส้นทางได้หรือเราเพิ่งได้รับคำตอบสุดท้าย?
hackjutsu

สิ่งนี้เรียกสำหรับทุกคำขอและถ้าฉันรู้ถูกต้องเป็นเพราะคุณเพิ่มมันเป็นตัวสกัดกั้นไม่ใช่เป็นตัวดักจับเครือข่าย ฉันคิดว่าคุณจะได้รับคำตอบสุดท้ายเท่านั้นที่นี่ แต่อาจมีการกำหนดค่าที่อนุญาตให้เห็นการเปลี่ยนเส้นทางเป็นการเปลี่ยนเส้นทางที่ฉันไม่รู้จากด้านบนของหัว (มีหนึ่งสำหรับการเชื่อมต่อ http URL ด้วย)
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;
    }
}

ดี! จึงrequest.newBuilder().headers(moreHeaders).build()จะคงส่วนหัวเดิมไว้?
hackjutsu

1
ใช่. ไม่มีส่วนหัวจะถูกลบออกจากคำขอเว้นแต่removeAll (ชื่อ String)จะเรียกว่า
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 ด้วยวิธีการในตัวเช่นนี้

   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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.