dio
dio copied to clipboard
Add QueuedInterceptor instead of interceptors.lock
What is QueuedInterceptor
?
As we all know, we can intercept requests/responses/errors before they are handled by then
or catchError
with
dio Interceptor
。In previous versions, interceptors could be executed concurrently, that is, all of the requests enter the interceptor at once, rather than executing sequentially. However, in some cases we expect that requests enter the interceptor sequentially like #590 。 Therefore, we need to provide a mechanism for sequential access(one by one) to interceptors and QueuedInterceptor
is proposed to solve this problem.
Examples
We make 3 concurrent requests, all of which enter the interceptor at the same time when using Interceptor
; But when using QueuedInterceptor
, requests enter the interceptor sequentially.
void main() async {
var dio = Dio();
dio.options.baseUrl = 'http://httpbin.org/status/';
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (
RequestOptions requestOptions,
RequestInterceptorHandler handler,
) {
print(requestOptions.uri);
Future.delayed(Duration(seconds: 2), () {
handler.next(requestOptions);
});
},
),
);
print( 'All of the requests enter the interceptor at once, rather than executing sequentially.');
await makeRequests(dio);
print( 'All of the requests enter the interceptor sequentially by QueuedInterceptors');
dio.interceptors
..clear()
..add(
// [QueuedInterceptorsWrapper] is a helper class, which is used to conveniently create QueuedInterceptor.
QueuedInterceptorsWrapper(
onRequest: (
RequestOptions requestOptions,
RequestInterceptorHandler handler,
) {
print(requestOptions.uri);
Future.delayed(Duration(seconds: 2), () {
handler.next(requestOptions);
});
},
),
);
await makeRequests(dio);
}
Future makeRequests(Dio dio) async {
try {
await Future.wait([
dio.get('/200'),
dio.get('/201'),
dio.get('/201'),
]);
} catch (e) {
print(e);
}
}
Of course, you can implement your own queued interceptor directly by inheriting from QueuedInterceptor
.
Delete Lock
s of interceptors
Locks of interceptors were originally designed to synchronize interceptor execution, but locks have a problem that once it becomes unlocked all of the requests run at once, rather than executing sequentially. Now QueuedInterceptor
can do it better.
To delete Lock
another reason is that Lock
is shared between the interceptors, so Lock can be called by any interceptors at any place, it will bring potential risks, assuming a interceptor invokes lock
, but because the code defects, lead to can't normal call unLock
, this will affect the rest of the interceptor to normal work (may never be executed to).
How to try QueuedInterceptor
.
Use 4.0.2-beta1
or change to develop
branch.
It works for me! 💯
Why do you deprecate locks? Could you provide example of token refreshment? In that case you need lock only for one part of the interceptor. (In the case where you repeat request)
Could you provide migration guide for requestLock
and responseLock
. It's not really clear to me how to replace it.
requestLock
and responseLock
can be removed. They were used to prevent concurrent interceptors which is now handled by QueuedInterceptor
@RumoneAnderson So by simply removing and replacing InterceptorWrapper
with QueuedInterceptorsWrapper
it's guaranteed the behaviour will be the same?
Being a guarantee that it will work for you, not sure. However, I have tested it and it works as expected.
How to clear a QueuedInterceptor's queue for cases when auth token unable to be refreshed? in 4.0.4 dio.clear() method are only clears lock's queue
We use the locks to deal with expired tokens and I'm not too comfortable changing this without good documentation.
Could someone please provide a concrete migration example for this?
How to clear a QueuedInterceptor's queue for cases when auth token unable to be refreshed? in 4.0.4 dio.clear() method are only clears lock's queue
this case cannot be handled currently with QueuedInterceptor. before with could clear unlock QueuedInterceptor holds ques internally no way to reset.
after token refresh failed interceptor becames inactive no error or result and we getting loading with no result.
with this new changes. what is the solution for refreshing tokens ?
Why do you deprecate locks? Could you provide example of token refreshment? In that case you need lock only for one part of the interceptor. (In the case where you repeat request)
A example for refreshing tokens with QueuedInterceptor : https://github.com/flutterchina/dio/blob/develop/example/lib/queued_interceptor_crsftoken.dart
How do I lock/unlock the requests?
It looks not so good to me, in my scenario.
I am using requestLock
in my project for temporarily locking a dio
instance and using another instance (with different Cookie jars, so they have to be held separately) to request a token for the former.
Since the token could be expired at any time, I have to check every response of the first dio
and decide whether it is necessary to get a new token and replay the request. In that case, with requestLock
I can simply lock the first, request a new token and unlock it.
But it isn't so easy to me when using a QueuedInterceptor
. When should the requests of the first dio
be blocked? It seems much harder to implement the function.
I am using
requestLock
in my project for temporarily locking adio
instance and using another instance (with different Cookie jars, so they have to be held separately) to request a token for the former one.
I'd like to know this as well. My code contains multiple dio instances, some of them are set up differently. At the moment I can decide which ones to lock/unlock etc.
Is sample auth interceptor https://gist.github.com/TimurMukhortov/a1c9819e3779015e54bc3964b7d2308a for dio. its work for me.
@wendux
l. My code contains multiple dio instances, some of them are set up differently. At the moment I can decide which ones to lock/unlock etc.
There is a problem with this implementation code, if an error is reported when dio.fetch()
is called in onError, the error will not be passed to the outside.
Here is sample code: https://github.com/ipcjs/dio/pull/1
I don't understand the need to deprecate the .clear()
method. There is a chance someone might want to clean the waiting queue even if they are using QueuedInterceptor
implementation.
For e.g. There might be repeated duplicate requests to the same endpoint, while the token is being refreshed. All of them get inserted in the queue, ready to run after the token is refreshed. However, after it is done, I might only want to execute the original request once, with the new token, and remove all the other duplicate requests. How is it possible to achieve this without clearing the queue?
@wendux
l. My code contains multiple dio instances, some of them are set up differently. At the moment I can decide which ones to lock/unlock etc.
There is a problem with this implementation code, if an error is reported when
dio.fetch()
is called in onError, the error will not be passed to the outside. Here is sample code: ipcjs#1
using with legacy it work properly but with QueuedInterceptorsWrapper not.
the problem is at line 428 if (!taskQueue.processing) { return true but taskQueue.queue is empty it get stucks.
@fullfash I have create a PR(#1457 ) to fix the queued_interceptor_crsftoken bug.
The key point to note about using QueuedInterceptor
is that the current dio instance is already blocked and another dio instance needs to be used to execute the request.
@ipcjs but same situation can be happen on second dio instance also.
Don't add a QueuedInterceptor
to the second dio instance, so it won't be blocked. 😅
yes but wondering if there can be any leaking case. 🤔 on repeat request there might be also a token expiration very small chance but... there must be an error prone fix for QueuedInterceptor logic.
anyway thanks . we will use tokenDio for repeat request also
I don't understand the need to deprecate the
.clear()
method. There is a chance someone might want to clean the waiting queue even if they are usingQueuedInterceptor
implementation.For e.g. There might be repeated duplicate requests to the same endpoint, while the token is being refreshed. All of them get inserted in the queue, ready to run after the token is refreshed. However, after it is done, I might only want to execute the original request once, with the new token, and remove all the other duplicate requests. How is it possible to achieve this without clearing the queue?
@wendux @ipcjs can somebody clear this for me?
@fullflash you are right. maybe we need add a repeatDio
, like this: https://github.com/ipcjs/dio/commit/dfe102d5bed4da72e8f77f8f67395ba2b7d47b40
🤔️
@ipcjs this is a good workaround. but i am still trying find a fix for QueuedInterceptor. there should be url mapping for overriding duplicate url request queues and that can fix the stuck on repeated dio calls.
@ipcjs our repeated request error bug is about QueuedInterceptors error handler.
i came we this patch: to keep active processing que and force complete when same request path and data repeats.
if (taskQueue.activeQueue != null &&
taskQueue.processing &&
handler is ErrorInterceptorHandler) {
final DioError cur = data as DioError;
final DioError a = taskQueue.activeQueue!.data! as DioError;
if (a.requestOptions.path == cur.requestOptions.path &&
a.requestOptions.data == cur.requestOptions.data) {
// taskQueue.processing = false;
final ErrorInterceptorHandler activeErrHandler =
taskQueue.activeQueue!.handler;
activeErrHandler.next(taskQueue.activeQueue!.data);
}
}
this bypasses your test. Will use such hardcoded way of dio package and make some tests to be sure.
To modify the lib
you need to ask the maintainer of the project. @wendux @kuhnroyal
I think it is better to modify the example
.
How to clear the queue? I got refreshing token happening 5 times to refresh the token. Is there a way to clear the queue?
Thank @ipcjs for your suggestion.
About this sample https://github.com/flutterchina/dio/blob/dfe102d5bed4da72e8f77f8f67395ba2b7d47b40/example/lib/queued_interceptor_crsftoken.dart
If you use another Dio instance to repeat the request (line 107 and line 83), everything should be working.
For this new Dio instance, don't forget to add your QueuedInterceptorsWrapper interceptor too.
Dio library does not seem to be maintained anymore ... does it?
Thank @ipcjs for your suggestion.
About this sample https://github.com/flutterchina/dio/blob/dfe102d5bed4da72e8f77f8f67395ba2b7d47b40/example/lib/queued_interceptor_crsftoken.dart
If you use another Dio instance to repeat the request (line 107 and line 83), everything should be working.
For this new Dio instance, don't forget to add your QueuedInterceptorsWrapper interceptor too.
Dio library does not seem to be maintained anymore ... does it?
unfortunately it looks abandoned. need alternative for "no hello world" applications )
Zead Is Dead Baby https://www.youtube.com/watch?v=zgGFK5drCpk