2016-06-10 4 views
11

내 업그레이드 2 (2.0.2 현재) 클라이언트는 요청에 사용자 지정 헤더를 추가해야합니다. 를 들어,개조 2 - API 수준에서 헤더를 추가하는 우아한 방법

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

항상 추가 할 일부 헤더하지만 일부 헤더는 난 단지 특정 엔드 포인트의 요구 사항에 따라 추가해야합니다

나는 모든 요청에이 헤더를 추가 할 Interceptor을 사용하고 있습니다 사용자가 인증을 받아야하는지 여부

내가 주석을 사용하여 예를 들어, API를 수준에서 그것을 제어 할 수있는 능력을 가지고 싶은, 뭔가 같은 : 인증 토큰을 추가 할 필요가 없습니다

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 주석이없는 요청에는 토큰 헤더가 있습니다.

Retrofit 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

@panduka 아니, 그건 그냥 예를 들어, 당신은 하나의 클라이언트를 가질 수 있습니다. –

+0

이것은 공유하기 덕분에 실제로 가장 깨끗한 해결책입니다. – MatPag

4

아마도 이와 같은 다른 Retrofit 객체 팩토리 메소드를 생성하면됩니다.

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

을 그리고 당신은 인증 API를 호출 할 경우 createServiceWithAuth의 방법을 사용하십시오 :

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 메소드를 호출 할 수 있습니다

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

이 하나 이상의 "사용자 정의 주석을"갖고 싶어 경우에도 잘 작동
고맙습니다. 좋은 솔루션이지만 요청을 인증해야하는지 여부에 따라 여러 클래스의 끝점을 그룹화해야합니다. 그다지 편리하지는 않습니다. –

관련 문제