我在http:/some.api
有一个api和一个GET
端点data
,它需要通过通过POST
auth
端点接收到的承载令牌进行认证。给定的安全令牌每1小时过期一次,因此,如果我收到POST http:/some.api/auth
上的401消息,我需要发出一个GET http:/some.api/data
请求,续订访问令牌并使用新的令牌对data
进行相同的调用在我的客户不了解令牌的情况下访问令牌。当前示例提供了Call
类型,我可以在不停止的情况下从UI线程enqueue
(调用),类似于.net
的{{1}}功能。现在,如果我使用的是async/await
,那么我将总结整个逻辑,如下所示:
.net
并从UI线程中调用async Task<DataModel> GetDataAsync()
{
try
{
return await GetDataInternalAsync();
}
catch(InvalidTokenException)
{
await ReAuthenticateAsync();
return await GetDataInternalAsync();
}
}
,无需担心。但是,当前示例仅显示如何进行调用并通过调用方法“现场”处理结果,例如:
await GetDataAsync()
使用翻新来组织满足我需要的呼叫体系结构的方式是什么?
答案 0 :(得分:2)
我强烈建议您使用RxJava adapter,而不是使用普通的翻新Callbacks
。然后,您可以从Retrofit Client返回Observables
,这在链接不同的电话(例如,使用flatMap
运算符)时将使您的生活更加轻松。
要处理您提到的令牌认证逻辑,我将使用自定义OkHttp3 Authenticator进行。这样,您可以将所有身份验证逻辑(可能将在几乎所有API调用中使用)放在一个位置,并且OkHttp将在每次收到401响应时调用定义的逻辑来更新令牌。
public class CustomOkHttpAuthenticator implements Authenticator {
...
@Override
public Request authenticate(@NonNull Route route, @NonNull okhttp3.Response response) throws IOException {
if (response.code() == 401) {
// Call your refresh token endpoint, wait for the new token, and build
// again the original request using the new token you received.
}
return null;
}`
...
}
最后,在创建OkHttp客户端时,Retrofit将用于执行HTTP调用,请确保添加自定义Authenticator
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.connectTimeout(10, TimeUnit.SECONDS);
client.readTimeout(15, TimeUnit.SECONDS);
client.writeTimeout(15, TimeUnit.SECONDS);
...
client.authenticator(new CustomOkHttpAuthenticator());
OkHttpClient okHttpClient = client.build();
okHttpClientHolder.setOkHttpClient(okHttpClient);
...
您可以在this repository中查看完整的代码示例。
答案 1 :(得分:0)
尝试一下:
private static final int MAX_TRIES = 3;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getDataAsync(0);
}
private void getDataAsync(final int currentRetryCount) {
Call<DataModel> call = apiService.getData();
call.enqueue(new Callback<DataModel>() {
@Override
public void onResponse(@NonNull Call<DataModel> call, @NonNull Response<DataModel> response) {
if(currentRetryCount<MAX_TRIES && response.code()== HttpURLConnection.HTTP_UNAUTHORIZED){ //401
authRequest(currentRetryCount+1);
}
}
public void onFailure(@NonNull Call<DataModel> call, @NonNull Throwable t) {
// todo deal with the failed network request
}
});
}
private void authRequest(final int currentRetryCount){
Call<AuthResponse> call = apiService.authReq();
call.enqueue(new Callback<AuthResponse>() {
@Override
public void onResponse(@NonNull Call<AuthResponse> call, @NonNull Response<AuthResponse> response) {
getDataAsync(currentRetryCount);
}
@Override
public void onFailure(@NonNull Call<AuthResponse> call, @NonNull Throwable t) {
// todo deal with the failed network request
}
});
}
我添加了retryCount
来防止无限请求,像这样的cz链接请求也可以充当递归。