2013-08-28 43 views
62

我正在使用OAuth,每次发出请求时都需要将OAuth令牌放入我的标头中。我看到了@Header注释,但有没有办法让它参数化,以便我可以在运行时传入?Android Retrofit Parameterized @Headers

这里是

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

您可以将它们在运行时的概念?

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

你有没有想过这个?我需要在标题中传递令牌 – theSociableme

+0

我也在寻找解决方案,从文档听起来像[@Headers()](http://square.github.io/retrofit/javadoc/retrofit/ http/Header.html)方法_adds fields_中的标注逐个标题,但仅支持文字。 和[@Header(“参数”)字符串字符串](http://square.github.io/retrofit/javadoc/retrofit/http/Header。html)参数注释_replaces_标题与提供的值。 – nana

+1

同样在这里,无法找到如何使用改造时处理会话。 – feresr

回答

89

除了使用@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

由于RequestInterceptor是不再可用在改造2.0

+3

这并不直接相关,但如果您发现自己需要从请求对象获取值以生成授权标头,则需要扩展ApacheClient并在执行时复制请求对象(列表

headers = ...;请求requestNew = new Request(request.getMethod(),request.getUrl(),headers,request.getBody()); request = requestNew)。 – 2014-01-07 18:14:09

+1

这是一个把编码弄乱的技巧,更好地使用@ nana的回答 –

+0

RestAdapter依赖于Retrofit1,在Retrofit2中它是Retrofit。我会使用Retrofit2,所以如果使用'RequestInterceptor'作为上面的代码没有问题? –

45

是的,你可以在运行时传递它们。事实上,几乎和你输入的一样。这将是你的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注释,就像您的情况一样!

我感到十分困惑过,the documentation明确表示,它取代头,但它
它实际上是在增加与@Headers("hardcoded_string_of_liited_use")注释

希望这有助于;)

+0

我在文档中发现它不会替换现有标头:“请注意,标头不会互相覆盖。”检查http://square.github.io/retrofit/和“Header Manipulation” – zatziky

+0

这是个好消息,它一定是修复过的! – nana

27

接受的答案是旧版本的Retrofit。对于未来的观众的方式与Retrofit 2.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(); 

希望它可以帮助别人。 :)

+3

在dagger2的常见用法中,retrofit2将是单例,因此每次都不会创建httpclient。在这种情况下,UserLoggedIn()没有意义,我是对的吗?我目前唯一能看到的解决方案是在用户登录状态发生变化时强制进行改造2,以便在请求中添加或删除适当的头部信息..或者有一些明显的解决方案,我目前无法看到? 谢谢。 – bajicdusko

+0

@bajicdusko这是我完全相同的内容。你找到了解决方案吗?看起来很浪费,奇怪的是之前的版本更有效率。 – deed02392

+0

@ deed02392你可以设置一个复合的“拦截器”,你可以在后面设置或重置拦截器。不过,我认为将单独改造作为单身人士可能是早期优化的标志。创建一个新的改造实例没有任何开销:https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit2/Retrofit.java – pablisco