我使用这个来配置我的改装:
RestAdapter restAdapter = new RestAdapter.Builder()
//add headers to requests
.setRequestInterceptor(getAuthenticatedRequestInterceptor())
.setEndpoint(BASE_URL)
.setConverter(new GsonConverter(getGson()))
.build();
而GetAuthenticatedRequestInterceptor()
方法将头添加到请求:
public AccountRequestInterceptor getAuthenticatedRequestInterceptor() {
AccountRequestInterceptor interceptor = new AccountRequestInterceptor();
Map<String, String> headers = new HashMap<>();
String accessToken = null;
try {
accessToken = TokenProvider.getInstance(mContext).getToken();
} catch (InterruptedException e) {
}
headers.put(HeadersContract.HEADER_AUTHONRIZATION, O_AUTH_AUTHENTICATION + accessToken);
interceptor.setHeader(headers);
return interceptor;
}
getToken()
方法为:
private synchronized string getToken() throws InterruptedException {
if (!isRefreshing()) {
//This is very important to call notify() on the same object that we call wait();
final TokenProvider myInstance = this;
setRefreshing(true);
MyApplication.getRestClient().getAccountService().getRefreshedToken(mLoginData.getRefreshToken())
.subscribe(new Observer<LoginResponse>() {
@Override
public void onCompleted() {
synchronized (myInstance) {
setRefreshing(false);
myInstance.notifyAll();
}
}
@Override
public void onError(Throwable e) {
synchronized (myInstance) {
setRefreshing(false);
myInstance.notifyAll();
}
}
@Override
public void onNext(LoginResponse loginResponse) {
synchronized (myInstance) {
mLoginData = loginResponse;
mAccountProvider.saveLoginData(loginResponse);
myInstance.notifyAll();
}
}
});
}
this.wait();
return mLoginData.getToken();
}
TokenProvider.GetInstance(mContext).GetToken()
在主线程上有一个wait()
来获取异步方法的响应,我知道这是一个不好的做法,但我需要这个方法来等待响应从其中获取令牌,然后返回令牌。我如何在一个单独的线程中这样做,以避免在主线程上等待?
注:
1-在任何带有改装的请求之前调用此命令。
2-我读了这篇文章,我知道我可以在请求失败后刷新令牌,但出于业务原因,我希望避免出现无效令牌。
3-我在我的activity
中调用MyApplication.GetRestClient().GetAccountService().Login(loginRequest,Callback...)
并且在添加令牌之前,所有事情都发生在后台线程中。所以我想使用我的令牌,不要阻塞主线程。
更新:我在新的OKHTTP中添加了以下拦截器
:
public class RequestTokenInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request newRequest;
try {
Log.d("addHeader", "Before");
String token = TokenProvider.getInstance(mContext).getToken();
if (token != null) {
newRequest = request.newBuilder()
.addHeader("Bearer", token)
.build();
} else {
// I want to cancel the request or raise an exception to catch it in onError method
// of retrofit callback.
}
} catch (InterruptedException e) {
Log.d("addHeader", "Error");
e.printStackTrace();
return chain.proceed(request);
}
Log.d("addHeader", "after");
return chain.proceed(newRequest);
}
}
现在,如果token为null,我如何取消请求或在reverfit回调的onError方法中引发一个异常来捕获它呢?
这是一个有点奇怪的问题,但让我试着帮你。:)
正如您所知,您可以使用响应拦截器在一个失败请求后通过修改刷新令牌。
让我们尝试在请求之前使用拦截器。
public class RequestTokenInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// Here where we'll try to refresh token.
// with an retrofit call
// After we succeed we'll proceed our request
Response response = chain.proceed(request);
return response;
}
}
在创建api时,创建一个新的HttpClient:
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new RequestTokenInterceptor());
并将http客户端添加到适配器,如下所示:
.setClient(new OkClient(client))
如果这样做有效,在每个请求之前,您将尝试首先刷新令牌,然后继续您的api请求。所以在ui中,与正常的api调用没有区别。
编辑:
我也在编辑我的答案。如果要在令牌为空的情况下返回一个else大小写中的错误,则可以在else大小写中创建自定义响应:
private Response(Builder builder) {
this.request = builder.request;
this.protocol = builder.protocol;
this.code = builder.code;
this.message = builder.message;
this.handshake = builder.handshake;
this.headers = builder.headers.build();
this.body = builder.body;
this.networkResponse = builder.networkResponse;
this.cacheResponse = builder.cacheResponse;
this.priorResponse = builder.priorResponse;
}
也可以简单地返回空响应。如果您构建自定义响应并将代码设置为不是200,例如401或400+,您将在改型的callbacks failure方法中收到该响应。你想做什么就做什么。
如果您返回null,我想您将得到一个RuntimeException,并且仍然可以在回调的failure方法中捕获响应。
在else中创建自己的响应后,您可以创建自定义回调,捕获空响应,并按需要转换自定义错误,如下所示:
public abstract class DefaultRequestCallback<T> implements Callback<T> {
public abstract void failure(YourCustomException ex);
public abstract void success(T responseBean);
@Override
public void success(T baseResponseBean, Response response) {
if (response == null) {
// Here we catch null response and transform it to our custom Exception
failure(new YourCustomException());
}
} else {
success(baseResponseBean);
}
}
@Override
public void failure(RetrofitError error) {
// Here's your failure method.
// Also you can transform default retrofit errors to your customerrors
YourCustomException ex = new YourCustomException();
failure(ex);
}
}
我想这能帮你。
编辑2:
您可以像下面这样构建一个新的响应。在Response类中有一个builder模式。你可以从那里查。
Response response = new Response.Builder().setCode(401).setMessage("Error Message").build();