Android --Retrofit2+Rxjava2 全局token自刷新

这篇博客是在这一篇博客的基础上进行优化完善的
与之相比,添加了全局自刷新token,失败自动重连,模块化、抽离网络请求模块成单独的library

实现全局自刷新token的逻辑并不复杂
  1. 添加token到Header
  2. 通过自定义的转换工厂,根据接口返回的token过期信息,抛出自定义token异常
  3. 获取最新的token,并且更换token
  4. 重新发起请求

添加header有多种方法
可以这样动态添加

	@POST()
	Flowable addHeader(@Header("token")String token);

	@POST()
	Flowable addHeader(@HeaderMap Map token);

也可以这样静态添加

	@Headers({"key:value","","",""})
    @POST()
    Flowable addHeader();

    @Headers("key:value")
    @POST()
    Flowable addHeader();

还可以这样

	OkHttpClient clients = new OkHttpClient.Builder()
                .addInterceptor(chain -> {
                    //为每一个请求添加token
                    Request request = chain.request().newBuilder().addHeader("token",“”).build();
                    return chain.proceed(request);
                })
                .build();

我这用的是第三种方法,全局添加token

之后是需要抛出token异常,在解析返回的数据时

	//处理Token过期异常数据
            if (jsonObject.get("message") instanceof String) {
                if ("tokenExpire".equals(jsonObject.getString("message")))
                    throw new TokenException();
            }

然后在retryWhen中处理

@Override
    public Publisher apply(Flowable throwableFlowable) throws Exception {

        return throwableFlowable.flatMap(throwable -> {
            if (throwable instanceof IOException || throwable instanceof HttpException) {
                if (count < maxCount) {
                    count++;
                    return Flowable.just(1).delay(time, TimeUnit.MILLISECONDS);
                } else {
                    return Flowable.error(new Throwable("重试次数已超过设置次数 = " + maxCount + ",即 不再重试"));
                }
            } else if (throwable instanceof TokenException) {
                return refreshToken();
            } else {
                return Flowable.error(new Throwable("发生了非网络异常(非I/O异常)"));
            }
        });

    }

    /**
     * 更新token
     * @return
     */
    private Flowable refreshToken() {
        synchronized (RetryWhen.class) {
            return mRetrofit.create(API.class).getToken()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .unsubscribeOn(Schedulers.io())
                    .doOnNext(tokenBean -> {
                        if (tokenBean != null && tokenBean.getData() != null && tokenBean.getData().getToken() != null) {
                            TempSettingConfig.SP_saveToken(tokenBean.getData().getToken());
                        }
                    });
        }
    }

创建代理

public  T createRemoteApi(Class clazz) {
        T api;
        try {
            api = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new ProxyHandler(retrofit.create(clazz)));
        } catch (Exception e) {
            e.printStackTrace();
            api = retrofit.create(clazz);
        }
        return api;
    }

通过添加代理来更新token

@Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        return Flowable.just(1).flatMap((Function>) o -> {
            try {
                try {
                    updateToken(method, args);
                    return (Publisher) method.invoke(mProxyObject, args);
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        };
    }

    /**
     * 更新token
     *
     * @param method 请求的方法
     * @param args   请求的参数
     */
    private void updateToken(Method method, Object[] args) {
        Annotation[][] annotationsArray = method.getParameterAnnotations();
        Annotation[] annotations;
        if (annotationsArray.length > 0) {
            for (int i = 0; i < annotationsArray.length; i++) {
                annotations = annotationsArray[i];
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Header) {
                        if (TOKEN.equals(((Header) annotation).value())) {
                            args[i] = TempSettingConfig.SP_getToken();
                        }
                    }
                }
            }
        }
    }

主要代码就是这些

源码在这

你可能感兴趣的:(日常记录)