改造:如何发送带有常量字段的POST请求?

2022-09-04 03:10:25

我想发送一个简单的POST请求,其中包含一个实际参数:

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

但是这个请求也应该发送一些由服务器请求的常量值,例如,这些值是常量的,不应该是应用程序API的一部分。client_idclient_secretgrant_type

最好的方法是什么?


答案 1

这取决于你的方法。如果您有常量,则可以构建调用所需的值的默认映射。 将适用于构建包含所有必填字段的地图@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);

答案 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 服务,以下逻辑都可以正常工作]

在我的网络模块中,我有以下内容来获取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等)。for method AuthWebservice.refreshToken

现在我创建了一个名为 的类,该类采用 .在大多数情况下,它只调用基本实例上的相应方法,除了我上面刚刚添加的方法:AuthWebserviceWrapperAuthWebservice

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
        )

}

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

@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

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


推荐