retrofit+rxjava 刷新token并發(fā)處理

1、引入:

最近項目中遇到一個很頭疼的問題,由于多接口并發(fā)請求刷新token失敗,導致app老是掉線要重新登錄。
當token過期處理首先想到的是在請求回調中獲取到token過期的信息,然后進行刷新操作,但是由于項目中使用到的網絡請求接口眾多,而且大多數接口都有可能會出現token過期的情況,如果多個接口同時去刷新token就會導致token失效,進而導致用戶需要重新登錄,對用戶的體驗非常不好。

2、實現思想:

由于項目中的token 是放在 http 請求的 header 中,所以這里使用okhttp 的攔截器來實現。當多個請求都出現了因 token過期而需要重新刷新 token的情況,那么需要判斷當前是否有另一個請求正在刷新 token,如果有,那么就不要發(fā)起刷新token的請求和其他請求,而是等待刷新 token的請求返回后,直接進行重試。

3、實現如下:

攔截數據判斷是否Token過期,并實現并發(fā)處理:

private Interceptor mTokenInterceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response originalResponse = chain.proceed(request);
        ResponseBody responseBody = originalResponse.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE);
        Buffer buffer = source.buffer();
        Charset charset = UTF8;
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(UTF8);
        }
        String bodyStr = buffer.clone().readString(charset);
        Gson gson = new Gson();
        HttpResult httpResult = gson.fromJson(bodyStr, HttpResult.class);
        String requestUrl=request.url().encodedPath();
        Log.e("Api","------------>request start>   request_url="+requestUrl);
        synchronized (getInstance()){//同步代碼塊,當在刷新token的時候暫停其他的request,鎖為當前類的單例對象
            //比較請求的token與本地存儲的token   如果不一致還是直接重試   
            String request_token=request.header("token");
            String access_token=TokenManager.getTokenInfo().getAccess_token();
            if(request_token!=null&&access_token!=null&&!request_token.equals(access_token)){
                Log.e("Api","------------>request retry   request_url="+requestUrl);
                Request newRequest=request.newBuilder().header("token", TokenManager.getTokenInfo().getAccess_token()).build();//等待的request重新拼裝請求頭
                return chain.proceed(newRequest);//重試request
            }
            if (httpResult.getCode()==10003){//10003是服務器與客戶端約定token過期的標識,在這里就執(zhí)行刷新token的操作
                Log.e("Api","------------>token longger");
                RequestToken requestToken = new RequestToken();
                requestToken.setRefresh_token("123456789");
                Call<HttpResult<TokenInfo>> call= Api.getInstance().service.refreshTokenSync(requestToken);
                 Log.e("Api","------------>refreshToken start");
                retrofit2.Response<HttpResult<TokenInfo>> response = call.clone().execute();//刷新token必須使用同步請求
                TokenInfo tokenInfo = response.body().getData();
                Log.e("Api","------------>refreshToken end  access_token="+tokenInfo.getAccess_token());
                TokenManager.saveTokenInfo(tokenInfo);//保存token
                isAlreadyRefreshToken=true;//當前請求已經刷新完token了
                Request newRequest=request.newBuilder().header("token", TokenManager.getTokenInfo().getAccess_token()).build();//重新拼裝請求頭
                return chain.proceed(newRequest);//重試request
            }
        }
        Log.e("Api","------------>request end>   request_url="+requestUrl);
        return originalResponse;
    }
};

添加攔截器:

OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(mTokenInterceptor)
                .build();

API

@PATCH("oauth/token")
Call<HttpResult<TokenInfo>> refreshTokenSync(@Body RequestToken requestToken);

并發(fā)請求的輸出日志

09-03 18:00:48.410 4702-6432/com.test E/Api: ------------>request start>   request_url=/interface/app_active
09-03 18:00:48.410 4702-6432/com.test E/Api: ------------>request end>   request_url=/interface/app_active
09-03 18:00:48.410 4702-6432/com.test E/Api: ------------>token longger
09-03 18:00:48.410 4702-6432/com.test E/Api: ------------>refreshToken start
09-03 18:00:48.414 4702-6430/com.test E/Api: ------------>request start>   request_url=/interface/app_version
09-03 18:00:48.421 4702-6456/com.test E/Api: ------------>request start>   request_url=/interface/hello
09-03 18:00:48.711 4702-6432/com.test E/Api: ------------>request start>   request_url=/interface/oauth/token
09-03 18:00:48.711 4702-6432/com.test E/Api: ------------>request end>   request_url=/interface/oauth/token
09-03 18:00:48.718 4702-6432/com.test E/Api: ------------>refreshToken end  access_token=i m a new token
09-03 18:00:49.516 4702-6430/com.test E/Api: ------------>request retry>   request_url=/interface/app_version
09-03 18:00:51.530 4702-6456/com.test E/Api: ------------>request retry>   request_url=/interface/hello
09-03 18:01:07.295 4702-6432/com.test E/Api: ------------>request start>   request_url=/interface/bat
09-03 18:01:07.295 4702-6432/com.test E/Api: ------------>request end>  request_url=/interface/bat
09-03 18:01:07.777 4702-6456/com.test E/Api: ------------>request start>   request_url=/interface/app_active
09-03 18:01:07.777 4702-6456/com.test E/Api: ------------>request end>   request_url=/interface/app_active

End

經過大量并發(fā)請求測試刷新token之后都不再出現token失效的問題,到這里就大功告成了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容