Okhttp refresh expired token when multiple requests are sent to the server

前端 未结 4 1277
北荒
北荒 2021-01-30 13:14

I have a ViewPager and three webservice calls are made when ViewPager is loaded simultaneously.

When first one returns 401, Authenticato

4条回答
  •  隐瞒了意图╮
    2021-01-30 14:17

    You can do this:

    Add those as data members:

    // these two static variables serve for the pattern to refresh a token
    private final static ConditionVariable LOCK = new ConditionVariable(true);
    private static final AtomicBoolean mIsRefreshing = new AtomicBoolean(false);
    

    and then on the intercept method:

    @Override
        public Response intercept(@NonNull Chain chain) throws IOException {
            Request request = chain.request();
    
            // 1. sign this request
            ....
    
            // 2. proceed with the request
            Response response = chain.proceed(request);
    
            // 3. check the response: have we got a 401?
            if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
    
                if (!TextUtils.isEmpty(token)) {
                    /*
                    *  Because we send out multiple HTTP requests in parallel, they might all list a 401 at the same time.
                    *  Only one of them should refresh the token, because otherwise we'd refresh the same token multiple times
                    *  and that is bad. Therefore we have these two static objects, a ConditionVariable and a boolean. The
                    *  first thread that gets here closes the ConditionVariable and changes the boolean flag.
                    */
                    if (mIsRefreshing.compareAndSet(false, true)) {
                        LOCK.close();
    
                        /* we're the first here. let's refresh this token.
                        *  it looks like our token isn't valid anymore.
                        *  REFRESH the actual token here
                        */
    
                        LOCK.open();
                        mIsRefreshing.set(false);
                    } else {
                        // Another thread is refreshing the token for us, let's wait for it.
                        boolean conditionOpened = LOCK.block(REFRESH_WAIT_TIMEOUT);
    
                        // If the next check is false, it means that the timeout expired, that is - the refresh
                        // stuff has failed.
                        if (conditionOpened) {
    
                            // another thread has refreshed this for us! thanks!
                            // sign the request with the new token and proceed
                            // return the outcome of the newly signed request
                            response = chain.proceed(newRequest);
                        }
                    }
                }
            }
    
            // check if still unauthorized (i.e. refresh failed)
            if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
                ... // clean your access token and prompt for request again.
            }
    
            // returning the response to the original request
            return response;
        }
    

    In this way you will only send 1 request to refresh the token and then for every other you will have the refreshed token.

提交回复
热议问题