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

问题描述

My Retrofit 2(当前 2.0.2 )客户端需要为请求添加自定义标头。



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

  OkHttpClient httpClient = new OkHttpClient(); 
HTTPClient.networkInterceptors().add(newInterceptor(){
@Override
响应拦截(链式链表)抛出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();

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



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

  public interface MyApi {
@NO_AUTH
@POST(register)
呼叫< RegisterResponse>寄存器(@Body RegisterRequest数据);

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

发送请求到 register 不需要添加身份验证令牌,但缺少 @NO_AUTH 注释的请求将拥有令牌头。



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



我想避免需要为每个请求传递这些头文件,如:

  public interface MyApi {
@POST(register)
呼叫< RegisterResponse>寄存器(@Body RegisterRequest数据);

@GET(user / {userId})
呼叫< GetUserResponse> getUser(@Header(AuthToken)字符串标记,@Path(userId)字符串userId);
}

每次我调用方法而不是做它在拦截器中(因为我可以静态访问标头值)。
我只是需要知道在我的 Interceptor.intercept 实现中是否或不是这个具体的请求应该有一个特定的头文件。



任何想法我可以做这个工作?

我更喜欢一个通用的解决方案,不仅针对身份验证令牌的情况,而且还提供特定的解决方案。
谢谢

解决方案

我想出了一个非常简单和优雅的解决方案(在我看来)可能用于其他场景。

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



因此基本上:

  public interface MyApi {
@POST(register )
@HEADERS(@:NoAuth)
呼叫< RegisterResponse>寄存器(@Body RegisterRequest数据);

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

然后我可以拦截请求,检查是否有名称为 @ 。如果是这样,我得到的价值,并从请求中删除头。

即使你想有多个自定义注释,这很有效:

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


$ b

以下是如何提取所有这些自定义注释并将它们从请求中移除的方法:

  new OkHttpClient.Builder()。addNetworkInterceptor(new Interceptor(){
@Override
public okhttp3.Response拦截(链式链)throws IOException { b $ b Request request = chain.request();

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

// do custom annotations

request = request.newBuilder()。removeHeader(@)。build();
return chain.proceed(request);
}
});


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

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.

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

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.

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

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.

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.

So basically:

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

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

10-20 12:39