本文介绍了Retrofit 2 - 在 api 级别添加标题的优雅方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Retrofit 2(当前为 2.0.2)客户端需要向请求添加自定义标头.

My Retrofit 2 (2.0.2 currently) client needs to add custom headers to requests.

我正在使用 Interceptor 将这些标头添加到所有请求中:

I'm using an Interceptor to add these headers to all requests:

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

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

Some headers I always want to add, but some headers I only need to add based on requirements of that specific endpoint, for example whether the user needs to be authenticated or not.

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

I'd like to have the ability to control that at the api level, for example using an annotation, something like:

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注解的请求会有令牌头.

When sending a request to register there's no need to add the authentication token, but requests who lack the @NO_AUTH annotation will have the token header.

据我所知,Retrofit 2 不支持自定义注释,虽然我找到了 Retrofit 2 的自定义注解,似乎有点太多了.

From what I understand Retrofit 2 doesn't support custom annotations, and while I found this workaround for Custom Annotations with Retrofit 2, it's seems a bit too much.

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

I'd like to avoid the need to pass these headers per request, like:

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 实现中知道这个特定的请求是否应该有一个特定的标头.

It just feels redundant to do it every time I call the method instead of doing it in the interceptor (since I have access to the header values statically).
I just somehow need to know in my Interceptor.intercept implementation whether or not this specific request should have a specific header(s).

知道如何使这项工作成功吗?
我更喜欢通用解决方案,而不仅仅是针对身份验证令牌的情况,但也欢迎使用特定的解决方案.谢谢

Any idea how I can make this work?
I prefer a generic solution and not just for the auth token case, but a specific solution is welcome as well.Thanks

推荐答案

我想出了一个非常简单和优雅(在我看来)的解决方案来解决我的问题,并且可能适用于其他场景.

I came up with a very simple and elegant (in my opinion) solution to my problem, and probably for other scenarios.

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

I use the Headers annotation to pass my custom annotations, and since OkHttp requires that they follow the Name: Value format, I decided that my format will be: @: 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);
}

然后我可以拦截请求,检查我是否有名称为@的注解.如果是这样,我会获取该值并从请求中删除标头.
即使您想要多个自定义注释",这也很有效:

Then I can intercept the request, check whether I have an annotation with name @. If so, I get the value and remove the header from the request.
This works well even if you want to have more than one "custom annotation":

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

以下是提取所有这些自定义注释"并将其从请求中删除的方法:

Here's how to extract all of these "custom annotations" and remove them from the request:

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

这篇关于Retrofit 2 - 在 api 级别添加标题的优雅方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 07:54