Retrofit 2 – 在api级别添加标头的优雅方式

我的Retrofit 2(当前2.0.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(); 

我总是想添加一些标头,但是我只需要根据特定端点的要求添加一些标头,例如用户是否需要进行身份validation。

我希望能够在api级别控制它,例如使用注释,例如:

 public interface MyApi { @NO_AUTH @POST("register") Call register(@Body RegisterRequest data); @GET("user/{userId}") Call getUser(@Path("userId") String userId); } 

发送register请求时,无需添加身份validation令牌,但缺少@NO_AUTH注释的请求将具有令牌头。

根据我的理解,Retrofit 2不支持自定义注释,虽然我发现使用Retrofit 2的自定义注释的这种解决方法,但它似乎有点太多了。

我想避免每个请求传递这些标头的需要,例如:

 public interface MyApi { @POST("register") Call register(@Body RegisterRequest data); @GET("user/{userId}") Call getUser(@Header("AuthToken") String token, @Path("userId") String userId); } 

每次调用方法而不是在拦截器中执行它时都会感觉多余(因为我可以静态访问标头值)。
我只是需要在我的Interceptor.intercept实现中知道这个特定的请求是否应该有一个特定的头。

知道如何让这个工作吗?
我更喜欢通用的解决方案而不仅仅是auth令牌案例,但也欢迎特定的解决方案。 谢谢

我提出了一个非常简单和优雅(在我看来)解决我的问题的方法,可能还有其他方案。

我使用Headers注释来传递我的自定义注释,并且由于OkHttp要求它们遵循Name: Value格式,我决定我的格式为: @: ANNOTATION_NAME

所以基本上:

 public interface MyApi { @POST("register") @HEADERS("@: NoAuth") Call register(@Body RegisterRequest data); @GET("user/{userId}") Call 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 customAnnotations = request.headers().values("@"); // do something with the "custom annotations" request = request.newBuilder().removeHeader("@").build(); return chain.proceed(request); } }); 

也许你可以通过创建这样的不同的Retrofit对象工厂方法来做到这一点。

 public class RestClient { public static  S createService(Class 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 createServiceWithAuth(Class 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); } } 

如果你想在没有头部身份validation的情况下调用api,你可以调用createService方法:

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

如果要通过身份validation调用api,请使用createServiceWithAuth方法:

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