package com.jh.jtestone.net;
import android.text.TextUtils;
import com.jh.jtestone.callback.IGlobalManager;
import com.jh.jtestone.net.exception.TokenInvalidException;
import com.jh.jtestone.net.exception.TokenNotExistException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
/**
* Created by 暗号 on 2017/9/3.
*/
public class ProxyHandler implements InvocationHandler{
private final static String TAG = "Token_Proxy";
private final static String TOKEN = "token";
private final static int REFRESH_TOKEN_VALID_TIME = 30;
private static long tokenChangedTime = 0;
private Throwable mRefreshTokenError = null;
private boolean mIsTokenNeedRefresh;
private Object mProxyObject;
private IGlobalManager iGlobalManager;
public ProxyHandler(Object mProxyObject, IGlobalManager iGlobalManager) {
this.mProxyObject = mProxyObject;
this.iGlobalManager = iGlobalManager;
}
@Override
public Object invoke(Object o, final Method method,final Object[] objects) throws Throwable {
return Observable.just(null).flatMap(new Function<Object, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Object o) throws Exception {
try {
if(mIsTokenNeedRefresh){
updateMethodToken(method,objects);
}
return (Observable<?>) method.invoke(mProxyObject,objects);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return null;
}
}).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
if(throwable instanceof TokenInvalidException){
return refreshTokenWhenTokenInvalid();
}else if(throwable instanceof TokenNotExistException){
// Token 不存在,执行退出登录的操作。(为了防止多个请求,都出现 Token 不存在的问题,
// 这里需要取消当前所有的网络请求)
iGlobalManager.exitLogin();
return Observable.error(throwable);
}
return Observable.error(throwable);
}
});
}
});
}
/**
* Refresh the token when the current token is invalid.
*
* @return Observable
*/
private Observable<?> refreshTokenWhenTokenInvalid() {
synchronized (ProxyHandler.class) {
// Have refreshed the token successfully in the valid time.
if (new Date().getTime() - tokenChangedTime < REFRESH_TOKEN_VALID_TIME) {
mIsTokenNeedRefresh = true;
return Observable.just(true);
} else {
// call the refresh token api.
RetrofitUtil.getInstance().get(IApiService.class).refreshToken().subscribe(new Subscriber<TokenModel>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
mRefreshTokenError = e;
}
@Override
public void onNext(TokenModel model) {
if (model != null) {
mIsTokenNeedRefresh = true;
tokenChangedTime = new Date().getTime();
GlobalToken.updateToken(model.token);
Log.d(TAG, "Refresh token success, time = " + tokenChangedTime);
}
}
});
if (mRefreshTokenError != null) {
return Observable.error(mRefreshTokenError);
} else {
return Observable.just(true);
}
}
}
}
/**
* Update the token of the args in the method.
*
* PS: 因为这里使用的是 GET 请求,所以这里就需要对 Query 的参数名称为 token 的方法。
* 若是 POST 请求,或者使用 Body ,自行替换。因为 参数数组已经知道,进行遍历找到相应的值,进行替换即可(更新为新的 token 值)。
*/
private void updateMethodToken(Method method, Object[] args) {
if (mIsTokenNeedRefresh && !TextUtils.isEmpty(GlobalToken.getToken())) {
Annotation[][] annotationsArray = method.getParameterAnnotations();
Annotation[] annotations;
if (annotationsArray != null && annotationsArray.length > 0) {
for (int i = 0; i < annotationsArray.length; i++) {
annotations = annotationsArray[i];
for (Annotation annotation : annotations) {
if (annotation instanceof Query) {
if (TOKEN.equals(((Query) annotation).value())) {
args[i] = GlobalToken.getToken();
}
}
}
}
}
mIsTokenNeedRefresh = false;
}
}
}
App的Token
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- *在第一次调用registerForRemoteNotificationTypes方法时没有联网,则既不会调用di...
- 为什么要放弃session 现在的互联网环境中,集群是后台比较常见的情况,众所周知,session其实是一个jvm...
- 作为一种新兴的鉴权方案,Token 作为 Session ID 的替代品有许多天然优势,很多主流产品也从 Sess...
- 在APP开发过程中少不了全局token的使用,今天主要和大家分享一下NSUserDefaults的使用。 NSUs...
- 雨总,你好! 我在XX县城做街舞培训一年多了,生源并不是很多!我有大量的街舞知识,专业的技巧,创业的时候信心满满。...