2016-06-10 15 views
11

में हेडर जोड़ने का सुरुचिपूर्ण तरीका मेरा रेट्रोफिट 2 (2.0.2 वर्तमान में) क्लाइंट को अनुरोधों के लिए कस्टम हेडर जोड़ने की आवश्यकता है।रेट्रोफिट 2 - एपीआई स्तर

मैं सभी अनुरोधों के लिए इन हेडर जोड़ने के लिए एक Interceptor उपयोग कर रहा हूँ:

OkHttpClient httpClient = new OkHttpClient(); 
httpClient.networkInterceptors().add(new Interceptor() { 
    @Override 
    public Response intercept(Chain chain) throws IOException { 
     final Request request = chain.request().newBuilder() 
       .addHeader("CUSTOM_HEADER_NAME_1", "CUSTOM_HEADER_VALUE_1") 
       .addHeader("CUSTOM_HEADER_NAME_2", "CUSTOM_HEADER_VALUE_2") 
       ... 
       .addHeader("CUSTOM_HEADER_NAME_N", "CUSTOM_HEADER_VALUE_N") 
       .build(); 

     return chain.proceed(request); 
    } 
}); 


Retrofit retrofitClient = new Retrofit.Builder() 
     .baseUrl(baseUrl) 
     .client(httpClient) 
     .build(); 

कुछ हेडर मैं हमेशा जोड़ना चाहते हैं, लेकिन कुछ हेडर मैं केवल कि विशिष्ट endpoint की आवश्यकताओं के आधार पर जोड़ने की जरूरत है, के लिए उदाहरण के लिए उपयोगकर्ता को प्रमाणीकृत होना चाहिए या नहीं।

मैं एक एनोटेशन का उपयोग कर उदाहरण के लिए, एपीआई स्तर पर है कि नियंत्रित करने की क्षमता प्राप्त करना चाहते हैं, कुछ की तरह:

public interface MyApi { 
    @NO_AUTH 
    @POST("register") 
    Call<RegisterResponse> register(@Body RegisterRequest data); 

    @GET("user/{userId}") 
    Call<GetUserResponse> getUser(@Path("userId") String userId); 
} 

जब एक अनुरोध भेजने register को प्रमाणीकरण टोकन जोड़ने के लिए कोई आवश्यकता नहीं है , लेकिन @NO_AUTH एनोटेशन की कमी वाले अनुरोधों में टोकन हेडर होगा।

जो मैं समझता हूं उससे रेट्रोफिट 2 कस्टम एनोटेशन का समर्थन नहीं करता है, और जब मुझे Custom Annotations with Retrofit 2 के लिए यह कामकाज मिला, तो यह थोड़ा सा लगता है।

मैं अनुरोध के अनुसार इन हेडर, की तरह पारित करने के लिए की जरूरत से बचने के लिए करना चाहते हैं:

public interface MyApi { 
    @POST("register") 
    Call<RegisterResponse> register(@Body RegisterRequest data); 

    @GET("user/{userId}") 
    Call<GetUserResponse> getUser(@Header("AuthToken") String token, @Path("userId") String userId); 
} 

यह सिर्फ निरर्थक लगता है यह हर बार जब मैं बजाय इंटरसेप्टर में यह करने की विधि कॉल करने के लिए (के बाद से मेरे पास स्थिर रूप से हेडर मानों तक पहुंच है)।
मुझे किसी भी तरह से मेरे Interceptor.intercept कार्यान्वयन में जानने की आवश्यकता है या नहीं, इस विशिष्ट अनुरोध के पास एक विशिष्ट शीर्षलेख होना चाहिए या नहीं।

कोई विचार यह है कि मैं यह काम कैसे कर सकता हूं?
मैं केवल सामान्य टोकन मामले के लिए एक सामान्य समाधान पसंद करता हूं, लेकिन एक विशिष्ट समाधान भी आपका स्वागत है। धन्यवाद

उत्तर

22

मैं अपनी समस्या के लिए, और शायद अन्य परिदृश्यों के लिए एक बहुत ही सरल और सुरुचिपूर्ण (मेरी राय में) समाधान के साथ आया था।

मैं Headers एनोटेशन का उपयोग अपने कस्टम एनोटेशन पारित करने के लिए, और के बाद से OkHttp की आवश्यकता है कि वे Name: Value प्रारूप का पालन, मैंने तय कर लिया है कि मेरे प्रारूप होगा: @: ANNOTATION_NAME

तो मूल रूप से:

public interface MyApi { 
    @POST("register") 
    @HEADERS("@: NoAuth") 
    Call<RegisterResponse> register(@Body RegisterRequest data); 

    @GET("user/{userId}") 
    Call<GetUserResponse> getUser(@Path("userId") String userId); 
} 

तब मैं अनुरोध को रोक सकता, यह देखना होगा कि मैं नाम @ भी एक टिप्पणी है। यदि ऐसा है, तो मुझे मान मिलता है और अनुरोध से हेडर को हटा देता है।
यह अच्छी तरह से काम करता है, भले ही आप एक से अधिक "कस्टम एनोटेशन" करना चाहते हैं:

@HEADERS({ 
    "@: NoAuth", 
    "@: LogResponseCode" 
}) 

यहाँ कैसे इन "कस्टम एनोटेशन" के सभी निकालें और उन्हें अनुरोध से दूर करने के लिए है:

new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() { 
    @Override 
    public okhttp3.Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 

     List<String> customAnnotations = request.headers().values("@"); 

     // do something with the "custom annotations" 

     request = request.newBuilder().removeHeader("@").build(); 
     return chain.proceed(request); 
    } 
}); 
+0

क्या इसका मतलब है कि आप प्रत्येक अनुरोध के लिए नए '' 'OkHttpClient''' का उपयोग कर रहे हैं? –

+1

@ पांडुका नं। यह सिर्फ उदाहरण के लिए था, आपके पास एक ग्राहक हो सकता है। –

+0

यह वास्तव में सबसे साफ समाधान है, साझा करने के लिए धन्यवाद :) – MatPag

4

शायद आप इस तरह के विभिन्न रेट्रोफिट ऑब्जेक्ट फैक्ट्री विधि बनाकर ऐसा कर सकते हैं।

public class RestClient { 
    public static <S> S createService(Class<S> serviceClass) { 
     OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); 
     OkHttpClient client = httpClient.build(); 

     Retrofit retrofit = new Retrofit.Builder().baseUrl(APIConfig.BASE_URL) 
       .client(client) 
       .build(); 
     return retrofit.create(serviceClass); 
    } 

    public static <S> S createServiceWithAuth(Class<S> serviceClass) { 
     Interceptor interceptor = new Interceptor() { 
      @Override 
      public Response intercept(Chain chain) throws IOException { 
       final Request request = chain.request().newBuilder() 
         .addHeader("CUSTOM_HEADER_NAME_1", "CUSTOM_HEADER_VALUE_1") 
         .addHeader("CUSTOM_HEADER_NAME_2", "CUSTOM_HEADER_VALUE_2") 
         .build(); 

       return chain.proceed(request); 
      } 
     }; 
     OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); 
     httpClient.addInterceptor(interceptor); 
     OkHttpClient client = httpClient.build(); 

     Retrofit retrofit = new Retrofit.Builder().baseUrl(APIConfig.BASE_URL) 
       .client(client) 
       .build(); 
     return retrofit.create(serviceClass); 
    } 
} 

यदि आप शीर्ष लेख प्रमाणन के बिना API कॉल करना चाहते हैं, तो आप सिर्फ createService विधि कॉल कर सकते हैं:

YourApi api = RestClient.createService(YourApi.class); 

और createServiceWithAuth विधि का उपयोग करता है, तो आप प्रमाणीकरण के साथ एपीआई कॉल करना चाहते हैं:

YourApiWithAuth api = RestClient.createServiceWithAuth(YourApiWithAuth.class); 
+0

धन्यवाद, यह एक अच्छा समाधान है, लेकिन मुझे अनुरोध है कि अनुरोधों को प्रमाणीकृत करने की आवश्यकता है या नहीं, यह अलग-अलग वर्गों में एंडपॉइंट्स को एक साथ समूहित करने की आवश्यकता है, और यह बहुत सुविधाजनक नहीं है। –

संबंधित मुद्दे