Android--›Retrofit,OKHTTP3,Token拦截器(超级通用版)

相关库:
OkHttp3
Retrofit

需求分析
当请求任意接口时, 返回需要获取Token的错误时, 拿到token并且重新请求接口.

源码

public class TokenInterceptor implements Interceptor {
    private static final Charset UTF8 = Charset.forName("UTF-8");

    Charset charset;

    OnTokenListener tokenListener;

    /**
     * 重试次数
     */
    int tryCount = 1;

    StringBuilder responseBodyBuilder = new StringBuilder();

    public TokenInterceptor(OnTokenListener tokenListener) {
        this.tokenListener = tokenListener;
        charset = UTF8;
    }

    public TokenInterceptor(int tryCount, Charset charset, OnTokenListener tokenListener) {
        this.charset = charset;
        this.tokenListener = tokenListener;
        this.tryCount = tryCount;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originRequest = chain.request();

        if (tokenListener == null) {
            return chain.proceed(originRequest);
        }

        //拿到正常接口请求的数据
        Request tokenRequest = setToken(originRequest);

        Response originResponse = chain.proceed(tokenRequest);
        Response resultResponse = originResponse;

        if (tokenListener != null) {
            int index = 0;
            while (index++ < tryCount) {
                try {
                    Response oldResponse = resultResponse;
                    resultResponse = doIt(chain, originRequest, resultResponse);
                    if (oldResponse != resultResponse && tryCount > 1) {
                        //返回的结果不一样, 并且重试次数大于1
                        if (isTokenInvalid(resultResponse)) {
                            //再次判断返回结果是否是token失效
                        } else {
                            //token有效, 退出循环
                            break;
                        }
                    }
                } catch (Exception e) {
                    resultResponse = originResponse;
                    break;
                }
            }
        }
        return resultResponse;
    }

    private String getResponseBodyString(Response response) throws IOException {
        if (response == null) {
            return "";
        }

        responseBodyBuilder.delete(0, responseBodyBuilder.length());

        ResponseBody responseBody = response.body();
        if (responseBody != null
                && responseBody.contentType() != null
                && responseBody.contentLength() > 0) {

            BufferedSource source = responseBody.source();
            source.request(Long.MAX_VALUE);
            Buffer buffer = source.buffer();

            responseBodyBuilder.append(buffer.clone().readString(charset));
        }

        return responseBodyBuilder.toString();
    }

    /**
     * 通过返回结果, 判断token是否过期
     */
    private boolean isTokenInvalid(Response resultResponse) throws IOException {
        return tokenListener != null &&
                tokenListener.isTokenInvalid(resultResponse, getResponseBodyString(resultResponse));
    }

    /**
     * 获取token, 并且重新请求接口
     */
    private Response doIt(Chain chain, Request originRequest, Response resultResponse) throws IOException {
        Response result = resultResponse;
        //判断token是否过期
        if (isTokenInvalid(resultResponse)) {
            CountDownLatch countDownLatch = new CountDownLatch(1);

            //Token失效
            tokenListener.tryGetToken(countDownLatch);

            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //重新请求本次接口
            Request tokenRequest = setToken(originRequest);
            result = chain.proceed(tokenRequest);
        }
        return result;
    }

    /**
     * 为这个请求, 设置token信息
     **/
    private Request setToken(Request request) {
        Request result = request;
        if (tokenListener != null) {
            result = tokenListener.initToken(request);
        }
        return result;
    }

    public interface OnTokenListener {

        /**
         * 设置token
         */
        Request initToken(@NonNull Request originRequest);

        /**
         * 根据接口返回值, 判断token是否失效
         *
         * @return true token失效
         */
        boolean isTokenInvalid(@NonNull Response response, @NonNull String bodyString);

        /**
         * 重新获取token
         * 获取token成功之后, 请调用 {@link CountDownLatch#countDown()}
         */
        void tryGetToken(@NonNull CountDownLatch latch);
    }
}

使用方式


//初始化对象
 val tokenInterceptor = TokenInterceptor(object : TokenInterceptor.OnTokenListener {
 			//为请求设置token
           override fun initToken(originRequest: Request): Request {
               return originRequest.newBuilder()
                   .addHeader("token-header", "token value")
                   .build()
           }

			//判断接口返回值, 是否是token失效
           override fun isTokenInvalid(response: Response, bodyString: String): Boolean {
               val errorBean = bodyString.fromJson(ErrorBean::class.java)
               return errorBean.code == 401
           }

			//重新获取token
           override fun tryGetToken(latch: CountDownLatch) {
               UserHelper.login { data, error ->
                   latch.countDown()
               }
           }
       })

//添加拦截器
OkHttpClient.Builder()
            .addInterceptor(tokenInterceptor)


群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.

联系作者

点此快速加群

请使用QQ扫码加群, 小伙伴们都在等着你哦!

关注我的公众号, 每天都能一起玩耍哦!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页