改造:如何使用常量字段发送POST请求?

时间:2014-11-02 07:33:42

标签: java android http http-post retrofit

我想发送一个带有一个实际参数的简单POST请求:

@POST("/token")
@FormUrlEncoded
void extendSession(@Field("refresh_token")final String refreshToken);

但是此请求还应该发送服务器请求的一些常量值,例如client_idclient_secretgrant_type,它们是常量,不应该是应用程序API的一部分。

这样做的最佳方式是什么?

4 个答案:

答案 0 :(得分:9)

这是你的方法的问题。如果您有常量,则可以构建调用所需的默认值映射。 @FieldMap适用于构建包含所有必填字段的地图

private void extendSession(String token){
   Map params = buildDefaultParams();
   params.put("refreshToken", token);
   getRestAdapter().create(MyApi.class).extendsSession(params);
}
private Map buildDefaultParams(){
   Map defaults = new HashMap();
   defaults.put("client_id", CLIENT_ID);
   defaults.put("client_secret", CLIENT_SECRET);
   defaults.put("grant_type", GRANT_TYPE);
   return defaults;
}
  /**then you change your interface to this **/ 
    @POST("/token")
    @FormUrlEncoded
    void extendSession(@FieldMap() Map refreshToken);

答案 1 :(得分:2)

这个问题有点老了,但是我自己考虑了一段时间之后,才想到了这个。我很想听听任何想法!

按照标准,我在名为AuthWebservice的接口中定义了@POST:

interface AuthWebservice {

    @POST("oauth/token")
    @FormUrlEncoded
    fun refreshToken(
        @Field("grant_type")
        grantType: GrantType,

        @Field("client_id")
        clientId: String,

        @Field("client_secret")
        clientSecret: String,

        @Field("refresh_token")
        refreshToken: String
    ): Call<AccessToken>

}

[注意:我正在使用Dagger进行依赖项注入,但是无论您在何处实例化Web服务,以下逻辑都将起作用]

在我的NetworkModule中,我具有以下内容以获得AuthWebservice的实例:

@Module
class NetworkModule {
    ...

    @Provides
    @Singleton
    fun providesAuthWebservice(
        retrofit: Retrofit
    ): AuthWebservice = retrofit.create(AuthWebservice::class.java)

    ...
}

这是我的解决方案: 我还在AuthWebservice中包含以下方法定义:

fun refreshToken(refreshToken: String): Call<AccessToken>

请注意,没有任何类型的注释,并且该方法返回的数据类型与包含所有参数的版本相同。该进行编译,但是显然如果您尝试调用它,它将在运行时失败,类似于以下内容:

  

java.lang.IllegalArgumentException:需要HTTP方法注释   (例如,@ GET,@ POST等)。           方法AuthWebservice.refreshToken

现在,我创建一个名为AuthWebserviceWrapper的类,该类带有AuthWebservice的实例。在大多数情况下,它只是在基本实例上调用相应的方法,除了就是我上面刚刚添加的方法:

class AuthWebserviceWrapper(private val base: AuthWebservice) : AuthWebservice {

    // Just call the base method.
    override fun refreshToken(
        grantType: GrantType,
        clientId: String,
        clientSecret: String,
        refreshToken: String
    ): Call<AccessToken> = base.refreshToken(
        grantType, 
        clientId,
        clientSecret, 
        refreshToken)

    // Call the base method with defaults!
    override fun refreshToken(refreshToken: String): Call<AccessToken> = 
        base.refreshToken(
            GrantType.REFRESH_TOKEN, // Default value 
            BuildConfig.MY_CLIENT_ID, // Default value 
            BuildConfig.MY_CLIENT_SECRET,  // Default value
            refreshToken
        )

}

最后,回到NetworkModule,我包装Retrofit的默认实现,如下所示:

@Module
class NetworkModule {
    ...

    @Provides
    @Singleton
    fun providesAuthWebservice(
        retrofit: Retrofit
    ): AuthWebservice = AuthWebserviceWrapper(retrofit.create(AuthWebservice::class.java))

    ...
}

现在,当我调用refreshToken时,将获得具有默认值的方法:

class MyClass @Inject constructor(authWebservice: AuthWebservice) {

    fun doSomething(refreshToken: String) {
       val call = authWebservice.refreshToken(refreshToken)
    }

}

当然,这确实引入了一些样板,但我不是粉丝,但我认为最终这是进行Web服务调用的最简洁的方法,而无需引入对@Body@FieldMap的需求。 / p>

无论如何,那是我的故事,我坚持下去。

答案 2 :(得分:1)

您可以使用Java Method Invocation Builder

@GenerateMethodInvocationBuilder
public interface ServiceApi {
 @POST("/token")
 @FormUrlEncoded
 void extendSession(
  @Default("theToken") @Field("refresh_token") final String refreshToken,
  @Default("theId") @Field("client_id") final String clientId,
  @Default("theSecret") @Field("client_secret") final String clientSecret,
  @Default("theType") @Field("grant_type") final String grantType);
}

然后你可以调用api:

ServiceApiExtendedSessionBuilder.extendedSession()
 .withRefreshToken("theRefreshToken")
 .invoke(serviceApi);

答案 3 :(得分:1)

您的界面可以接受String对象而不是GrantType,而该对象具有针对不同grant_type的工厂方法。这些工厂方法将设置client_idclient_secretgrant_type字段。

@POST("/oauth/token")
Call<Token> extendSession(@Body GrantType grantType);