我正在使用authenticator
OKHttp
,如果我们遇到401
状态错误,我会重新尝试获取新的访问令牌,但我的应用已经同时调用许多API,导致数据损坏,因为存在的刷新令牌将在请求时被删除 - 但其他API调用者仍然依赖此令牌来使用。所以我的问题是:当我们得到401错误状态代码时,无论如何将请求放入队列(或至少取消)所有其他api请求?
这是我的身份验证员:
public Request authenticate(Route route, Response response) throws IOException {
// Refresh your access_token using a synchronous api request
access_token = getNewAccessTokenHere();
// Add new header to rejected request and retry it
return response.request().newBuilder()
.header("Authorization", "Bearer " + access_token)
.build();
} else {
ToastUtil.toast("login again");
return null;
}
}
我的目标是让其他api等待第一个请求的响应并使用新的access_token。
答案 0 :(得分:1)
您可以使用Dispatcher
访问所有正在进行的通话并取消它们。
https://square.github.io/okhttp/3.x/okhttp/okhttp3/Dispatcher.html
答案 1 :(得分:1)
我知道这个问题已经很老了,但我发现自己最近遇到了同样的问题而且我找到了一个对我有用的解决方案,我相信它可以帮助其他人处于同样的情况。
如Dispatcher所述,将Jake Wharthon附加到OkHttp客户端并限制最大请求数量的解决方案似乎不适用于开箱即用的改进。
所以我的解决方案是在我的自定义Authenticator上同步 身份验证方法,对我的单例Retrofit实例进行并发调用,等到身份验证例程为每个线程完成。这样,带有未经授权响应的第一次呼叫可以刷新令牌,并通知下一次呼叫,这也是未经授权的响应,新的访问令牌已经可用。
public class MyAuthenticator implements Authenticator {
private boolean isRefreshed = false;
// Call when a new request is being made. Concurrent request should call this method to enable the refresh routine
public void newRequest(){
isRefreshed = false;
}
@Nullable
@Override
public synchronized Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException { // Synchronize the method to avoid refreshing thread overlapping
if (responseCount(response) > 3) {
return null;
}
if (!isRefreshed){
// Refresh your access_token using a synchronous api request
String accessToken = getNewAccessTokenHere();
// Saves the new access token
saveNewAccessToken(accessToken);
isRefreshed = true;
// Add new header to rejected request and retry it
return response.request().newBuilder()
.removeHeader("Authorization") // removes the old header, avoiding duplications
.addHeader("Authorization", "Bearer " + accessToken)
.build();
}
else{ // Access token already refreshed so retry with the new one
// Get the saved access token
String accessToken = getAccessToken();
return response.request()
.newBuilder()
.removeHeader("Authorization")
.addHeader("Authorization", accessToken)
.build();
}
}
private int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}