Dio: Locking interceptors doesn't work when multiple requests are enqueued

Created on 5 Dec 2019  ·  13Comments  ·  Source: flutterchina/dio

New Issue Checklist

  • [x] I have searched for a similar issue in the project and found none

Issue Info

| Info | Value | |
| ------------------------------ | ----------------------------------------------------- | ---- |
| Platform Name | e.g. flutter | |
| Platform Version | e.g. master | |
| Dio Version | e.g. 3.0.7 | |
| Android Studio / Xcode Version | e.g. IntelliJ | |
| Repro rate | e.g. all the time (100%) |
| Repro with our demo prj | No | |

Issue Description and Steps

I'm using an interceptor with locks to lock the interceptor while a token is being refreshed. If multiple requests are enqueued while the lock is active, once it becomes unlocked, all of the requests run at once, rather than executing sequentially.

pinned

Most helpful comment

Don't stale this issue. It wasn't fixed yet.

All 13 comments

I'm having the same issue here. @athornz did you found a solution for this?

Don't stale this issue. It wasn't fixed yet.

Still a problem

I'm having the same issue. :(

Don't state yet

this is very important problem.
please share solution if someone have or alternative package.

I have the same problem. I used the same example as here [https://github.com/flutterchina/dio/issues/50]. When I have few requests with authorization header, every request with invalid token (status 401) do refresh token.
Looks like

dio.interceptor.request.lock();
dio.interceptor.response.lock();

works separately for every request, but not for whole bunch of requests.

I kinda found a work around using static class.
So every request would be statically invoke, not a new instance.

class DioWrapper {
  static Dio http = Dio();

  static Dio get httpWithoutInterceptors {
    return Dio(http.options);
  }

  static Options defaultCache = buildCacheOptions(
    Duration(days: 7),
    forceRefresh: true,
  );

  static bool locked = false; // <---- HERE

  static bool get hasToken => (http.options.headers['Authorization'] != null);

  static DioCacheManager _cacheManager = DioCacheManager(
    CacheConfig(baseUrl: http.options.baseUrl),
  );

  static InterceptorsWrapper _mainInterceptor = InterceptorsWrapper(
    onRequest: (RequestOptions options) async {
      return options;
    },
    onResponse: (Response response) async {
      return response;
    },
    onError: (DioError e) async {
      if (e.response != null) {
        String $errorMessage = e.response.data['message'];
        if (e.response.statusCode == 401) {
          if (!locked) {
            locked = true; //unlock in AuthModel
            Get.snackbar(
              'Session Expired',
              'Please Login Again!',
              duration: Duration(seconds: 10),
            );
            logout();
          }
        } else {
          Get.defaultDialog(
            title: 'Error',
            onCancel: () => {},
            textCancel: 'Close',
            cancelTextColor: Colors.red,
            buttonColor: Colors.red,
            middleText: $errorMessage,
          );
        }
        return http.reject($errorMessage);
      } else {
        Get.snackbar(
          'Sever Error',
          'Please Check Connection!',
          duration: Duration(seconds: 10),
        );
        return http.reject(e.message);
      }
    },
  );

  static void setupDioWrapperHttp() {
    http.options.headers['X-Requested-With'] = 'XMLHttpRequest';
    http.options.baseUrl = 'https://api';
    http.interceptors.add(_mainInterceptor);
    http.interceptors.add(_cacheManager.interceptor);
    http.interceptors.add(LogInterceptor(
      request: false,
      requestHeader: false,
      responseHeader: false,
    ));
  }

  static void addTokenHeader(String token) {
    http.options.headers['Authorization'] = 'Bearer $token';
  }

  static Future<void> checkTokenInSharedPreference() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String token = prefs.getString('apiToken');
    if (token != null) {
      addTokenHeader(token);
    }
  }

  static void logout() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.remove('apiToken');
    addTokenHeader(null);
    Get.offAllNamed(RouterTable.login);
  }
}

main

void main() {
  FluroRouter.setupRouter();
  DioWrapper.setupDioWrapperHttp();
  runApp(HomePage());
}

usage

DioWrapper.http.get(...);
DioWrapper.locked = false;

Yes but, this need to be fixed by the Dio team, and seems that they are not interessed to fix this

Yes but, this need to be fixed by the Dio team, and seems that they are not interessed to fix this

Yes. looks like this package abandoned.

I have the same problem. I used the same example as here [https://github.com//issues/50]. When I have few requests with authorization header, every request with invalid token (status 401) do refresh token.
Looks like

dio.interceptor.request.lock();
dio.interceptor.response.lock();

works separately for every request, but not for whole bunch of requests.

First, Please make sure all multiple requests are Initiated by the same one dio instance.

Then, Please check out:
https://github.com/flutterchina/dio/blob/master/example/interceptor_lock.dart
https://github.com/flutterchina/dio/blob/master/dio/test/interceptor_test.dart

multiple requests

Why executing sequential is need? What is the senior ?
If you really need to execute sequentially, you can do this as follows:

// enter `onResponse` one by one
 ...
onResponse: (){
 dio.interceptors.responseLock.lock();

  // do anything
  ...
 dio.interceptors.responseLock.unlock();
}

I have the same issue, definitely not fixed in 3.0.10

Was this page helpful?
0 / 5 - 0 ratings