【发布时间】:2019-11-20 03:19:46
【问题描述】:
我在 REST API 中有以下端点:
public interface AutomoticzAPI {
@POST("/api/beacon_auth/login")
Single<LoginResponse> login(@Body LoginRequest request);
@GET("/api/system/ws_devices")
Single<WSDevicesResponse> wsDeviceList(@Header("Authorization") String tokenHeader);
}
当我调用login 端点时,作为响应,我收到了保存到ClientSession 持有者对象中的访问令牌。稍后我可以从ClientSession 检索令牌用于调用服务器的受保护资源:
api.login(ClientSession.getInstance().getLoginRequest(login, password))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(loginResponse -> {
String accessToken = loginResponse.getAccessToken();
ClientSession.getInstance().setAccessToken(accessToken);
view.onLoginSuccess();
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
if (exception.getKind().equals(RetrofitException.Kind.HTTP)){
view.onLoginFailed(exception.getMessage());
} else if(exception.getKind().equals(RetrofitException.Kind.NETWORK))
{
view.onLoginFailed("Network error...");
} else {
view.onLoginFailed("Unknown error occurred...");
}
});
当我调用wsDeviceList 端点时,服务器可以返回 401 HTTP 响应代码和带有错误代码和消息的 json 正文:
{
"code": "EXPIRED-TOKEN",
"message": "Token expired"
}
如果发生这种情况,我想再次调用登录端点以获取新的访问令牌。到目前为止,这是我的代码:
ClientSession clientSession = ClientSession.getInstance();
String token = "Bearer "+clientSession.getAccessToken();
String url = ClientSession.getInstance().getUrl();
AutomoticzAPI api = NetworkManager.getApiClient(url);
api.wsDeviceList(token)
.retryWhen(throwableFlowable -> throwableFlowable.flatMap(
new Function<Throwable, Publisher<?>>() {
@Override
public Publisher<?> apply(Throwable throwable) throws Exception {
RetrofitException exception = (RetrofitException) throwable;
if (exception.isUnauthorizedError()){
return relogin(api, clientSession.getLoginRequest());
}
return (Publisher<?>) throwable;
}
}
))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(wsDevicesResponse -> {
view.onDeviceListLoaded(wsDevicesResponse.getWsdevices());
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
view.onError(exception);
});
}
public Publisher<?> relogin(AutomoticzAPI api, LoginRequest loginRequest){
return (Publisher<?>) api.login(loginRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(loginResponse -> {
String accessToken = loginResponse.getAccessToken();
ClientSession.getInstance().setAccessToken(accessToken);
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
view.onError(exception);
});
}
但是当relogin 方法被执行时,我的程序崩溃了。
我不精通 RxJava,可能做错了。如何调用login 以刷新访问令牌,然后再次调用wsDeviceList?
【问题讨论】:
-
使用 Okhttps' Authenticator,它提供了一种机制来处理这种情况。 square.github.io/okhttp/recipes/#handling-authentication
标签: java android retrofit2 rx-java2