Android改装参数化@Headers


85

我正在使用OAuth,每次发出请求时,都需要将OAuth令牌放在标头中。我看到了@Header注释,但是有没有一种方法可以对其进行参数化,以便我可以在运行时传递?

这是概念

@Header({Authorization:'OAuth {var}', api_version={var} })

您可以在运行时传递它们吗?

@GET("/users")
void getUsers(
    @Header("Authorization") String auth, 
    @Header("X-Api-Version") String version, 
    Callback<User> callback
)

你有没有解决这个问题?我需要在令牌通过在头部还
theSociableme

我也在寻找一种解决方案,从文档中听起来像方法上的@Headers()批注将字段一一添加到标题中,但仅支持文字。和@Header(“参数”)的字符串的字符串参数注释替换与所提供的值的报头。
娜娜

2
同样在这里,找不到使用改造时如何处理会话。
FRR 2014年

我们不需要传递所有项目,改造本身就可以处理所有问题。请检查我的答案在StackOverflow中的链接
Babu

Answers:


98

除了使用@Header参数之外,我还希望使用RequestInterceptor来更新您的所有请求,而无需更改您的界面。使用类似:

RestAdapter.Builder builder = new RestAdapter.Builder()
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
            if (isUserLoggedIn()) {
                request.addHeader("Authorization", getToken());
            }                    
        }
    });

p / s:如果使用Retrofit2,则应使用Interceptor而不是RequestInterceptor

以来 RequestInterceptorRetrofit 2.0中不再提供


3
这没有直接关系,但是如果您发现自己需要从请求对象获取值以生成授权标头,则需要扩展ApacheClient并执行重复的请求对象(List <Header>标头= ... ; Request requestNew = new Request(request.getMethod(),request.getUrl(),标头,request.getBody()); request = requestNew)。

1
这是一个使编码混乱的技巧,最好使用
@nana

1
RestAdapter取决于Retrofit1,在Retrofit2中为Retrofit。我将使用Retrofit2,因此如果使用RequestInterceptor上述代码也没有问题?
休塔

55

是的,您可以在运行时传递它们。事实上,几乎与您键入的内容完全相同。这将在您的API接口类中,命名为SecretApiInterface.java

public interface SecretApiInterface {

    @GET("/secret_things")
    SecretThing.List getSecretThings(@Header("Authorization") String token)

}

然后,将您的请求中的参数传递给该接口,类似以下行:(此文件例如是SecretThingRequest.java

public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{

    private String token;

    public SecretThingRequest(String token) {
        super(SecretThing.List.class, SecretApiInterface.class);
        this.token = token;
    }

    @Override
    public SecretThing.List loadDataFromNetwork() {
        SecretApiInterface service = getService();
        return service.getSecretThings(Somehow.Magically.getToken());
    }
}

Somehow.Magically.getToken()返回令牌的方法调用在哪里,取决于您在何处以及如何定义令牌。

当然@Header("Blah") String blah,在您的情况下,接口实现中可以包含多个注解!

我也发现它令人困惑,文档明确指出它替代了标头,但事实并非如此
实际上是与@Headers("hardcoded_string_of_liited_use")注释一起

希望这可以帮助 ;)


1
我在文档中发现它不会替换现有的标头:“请注意,标头不会相互覆盖。” 检查square.github.io/retrofit和“头操作”
Amio.io 2014年

37

可接受的答案是旧版本的Retrofit。对于将来的观看者,使用Retrofit2.0进行此操作的方法是使用自定义OkHttp客户端:

OkHttpClient httpClient = new OkHttpClient.Builder()
  .addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
      Builder ongoing = chain.request().newBuilder();
      ongoing.addHeader("Accept", "application/json;versions=1");
      if (isUserLoggedIn()) {
        ongoing.addHeader("Authorization", getToken());
      }
      return chain.proceed(ongoing.build());
    }
  })
  .build();

Retrofit retrofit = new Retrofit.Builder()
  // ... extra config
  .client(httpClient)
  .build();

希望它能帮助某人。:)


5
在dagger2中,retrofit2通常是单例的,因此不会每次都创建httpclient。在这种情况下,isUserLoggedIn()没有意义,对吗?我当前只能看到的解决方案是在更改用户登录状态时强制Retrofit2重新初始化,以便从请求中添加或删除适当的标头。或者我目前无法看到某些明显的解决方案?谢谢。
bajicdusko,2016年

2
@bajicdusko这是我完全一样的难题。您找到解决方案了吗?似乎很浪费,而且很奇怪,以前的版本效率更高。
deed02392

@ deed02392您可以设置一个合成Interceptor,以后可以在其中设置或重置拦截器。但是,我认为将改装作为单身人士可能是早期优化的迹象。创建新的改造实例没有开销:github.com/square/retrofit/blob/master/retrofit/src/main/java/…– pablisco 2016
6

我并没有真正深思。我有一些ApiFactory类,它也用dagger2初始化,它负责改造的初始化。我在ApiFactory中公开了一个公共方法,该方法在需要时强制重新启动改造实例,因此非常简单。我可能做错了,但它确实完成了工作,并且我仅将其用于Authorization标头,因此在用户登录或注销时使用它。另一个选择是在端点定义内使用@Header批注,这对我来说是不可接受的。我应该在每个不可行的端点上设置它。
bajicdusko

@pablisco根据我的理解,Interceptor一旦创建Retrofit2实例,您将无法添加或删除。
deed02392

7

改造2.3.0

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder
            .addInterceptor(new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
                    return chain.proceed(newRequest.build());
                }
            });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubService.BASE_URL)
            .client(okHttpClientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

我正在使用它来连接到GitHub。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.