我想发送一个带有一个实际参数的简单POST请求:
@POST("/token")
@FormUrlEncoded
void extendSession(@Field("refresh_token")final String refreshToken);
但是此请求还应该发送服务器请求的一些常量值,例如client_id
,client_secret
和grant_type
,它们是常量,不应该是应用程序API的一部分。
这样做的最佳方式是什么?
答案 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_id
,client_secret
和grant_type
字段。
@POST("/oauth/token")
Call<Token> extendSession(@Body GrantType grantType);