Comments (19)
cc @seunghwanly to provide a detailed explanation.
from dio.
@AlexV525 Umm .. should I provide more clearer example than the current one? for clear understanding
Yeah feel free to request changes and then we can discuss
from dio.
@seunghwanly Thank you for your help. For me, your example is clear enough, and I understand the flow, but my point is what happen if final originResult = await dio.fetch(options..path += '&pass=true');
fails, and how to handle it.
- Should I use different dio instance for retry the original request onError?, but using different instances for the same request requires the same configuration for both instances?
- Should I call retried original request with in try-catch block or not?
dio/example/lib/queued_interceptor_crsftoken.dart
Lines 67 to 71 in ccc7666
@ykaito21's example at the top, using same instance might cause infinite loop and keep calling this cycle.
onRequest is called onError is calledcheck on debug mode (look for
hashCode
ofdio
) and see if same instance is requested all the time.
indeed, it is the same instance
from dio.
@seunghwanly, thanks for the detailed explanation and updated example.
I have a question about your example, I don't see a case in onError for an automatic retry with a new token, if I wanted to add that, could I just create a new dio in onError and use that like tokenDio?
/// Add `onError` interceptor to request new CSRF token dio.interceptors.add( QueuedInterceptorsWrapper( /// Request new CSRF token /// if the response status code is `401` onError: (error, handler) async { log('Error Detected: ${error.message}'); if (error.response == null) return handler.next(error); if (error.response?.statusCode == 401) { try { final tokenDio = Dio( BaseOptions(baseUrl: error.requestOptions.baseUrl), ); /// Generate CSRF token /// /// This is a MOCK REQUEST to generate a CSRF token. /// In a real-world scenario, this should be generated by the server. final result = await tokenDio.post( '/response-headers', queryParameters: { _headerKey: '94d6d1ca-fa06-468f-a25c-2f769d04c26c', }, ); if (result.statusCode == null || result.statusCode! ~/ 100 != 2) { throw DioException(requestOptions: result.requestOptions); } final updatedToken = result.headers.value(_headerKey); if (updatedToken == null) throw ArgumentError.notNull(_headerKey); cachedCSRFToken = updatedToken; // Can I do like this? or is there better way? final retryDio = Dio( BaseOptions(baseUrl: error.requestOptions.baseUrl), ); final requestOptions = err.requestOptions; requestOptions.headers['token'] = '$updatedToken'; final res = retryDio.fetch(requestOptions); return handler.resolve(res); } on DioException catch (e) { return handler.reject(e); } } }, ), );
Yes, I wrote the example for QueuedInterceptorsWrapper
to see callbacks handled in a row. And as it said before
The example does not contain retries, so 2 instances were used for the flow. More instances do not mean more resource costs because it just acts as a manager. Better start to use packages like dio_smart_retry.
use another dio to manage retry or other requests to handle exception cases. Here is an example for a retry interceptor.
from dio.
I updated example/lib/queued_interceptor_crsftoken.dart here. It seems to be more clear than before like handling errors and queued interceptors.
@seunghwanly Hi sorry for missing the thread. Could you submit the pull request?
from dio.
+1 any update one this ?
from dio.
You are reusing the same Dio
instance in callbacks, consider adding another instance for retries which could avoid deadlocks in the most of cases.
from dio.
You are reusing the same
Dio
instance in callbacks, consider adding another instance for retries which could avoid deadlocks in the most of cases.
You mean I have to use 3 different Dio
instances on refresh token and retry? But the queued_interceptor_crsftoken example uses the same instance on retry.
from dio.
You mean I have to use 3 different
Dio
instances on refresh token and retry? But the queued_interceptor_crsftoken example uses the same instance on retry.
The example does not contain retries, so 2 instances were used for the flow. More instances do not mean more resource costs because it just acts as a manager. Better start to use packages like dio_smart_retry
.
from dio.
The example does not contain retries, so 2 instances were used for the flow. More instances do not mean more resource costs because it just acts as a manager. Better start to use packages like
dio_smart_retry
.
Isn't that retry? final originResult = await dio.fetch(options..path += '&pass=true');.
I don't understand the difference from my case.
from dio.
cc @seunghwanly to provide a detailed explanation.
In my example, I've used 2 different instances for Dio
dio
: handles main request and responsetokenDio
: manages token, when token has expired or request failed with401
status code
dio/example/lib/queued_interceptor_crsftoken.dart
Lines 52 to 60 in ccc7666
on onError
callback, tokenDio
is used for token refresh and adds new 'token' to original dio(dio
: L7) as you can see at the last line (L60)
then when its token(csrfToken
) has been updated, which I pretended as not null
(!= null
). I tried a new request with original dio(dio
: L7) (new token added).
And for the result, I just added handler when it has succeeded (not for error) like below.
dio/example/lib/queued_interceptor_crsftoken.dart
Lines 68 to 71 in ccc7666
@ykaito21's example at the top, using same instance might cause infinite loop and keep calling this cycle.
onRequest is called
onError is called
check on debug mode (look for hashCode
of dio
) and see if same instance is requested all the time.
from dio.
@AlexV525 Umm .. should I provide more clearer example than the current one? for clear understanding
from dio.
Should I use different dio instance for retry the original request onError?, but using different instances for the same request requires the same configuration for both instances?
If we need updated data from the server, I'd rather use another instance for the request, and for the same configuration I made an example like the one below.
Or else I might not use a different instance to request a retrial. In that case things like changing the host from cached to its origin.
const originHost = 'origin.com';
const cachedHost = 'cached.origin.com';
final originDio = Dio();
... // [originDio]'s interceptor
onError: (error, handler) async {
/// Pretend we have an extension called [isTimeout]
/// returns `true` when the request past 2 min.
if (error.isTimeout) {
/// Set new host
dio.options.baseUrl = 'https://$cachedHost';
final result = await dio.fetch(dio.options);
/// handle result
// TODO
}
}
Should I call retried original request with in try-catch block or not?
This depends on your code style. I sometimes use the try-catch
block to handle specific status codes like 401, 403, 500, and so on. Or handling on 'Presentation Layer' like using Provider
, BLoC
, or RiverPod
.
I hope my answer was helpful enough. Please let me know if you need any further assistance. :)
If we use the same instance in the onError
callback and try to catch an error within the try-catch
block, we cannot reach the catch
block at all.. because the dio
will keep rolling between onRequest
and onError
's try block
P.S. I will soon request changes for the csrfToken example.
from dio.
I have a token refresh interceptor and now that I read this, I think I am actually seeing a similar behavior.
Need to look into this when I find some time.
from dio.
If we use the same instance in the
onError
callback and try to catch an error within thetry-catch
block, we cannot reach thecatch
block at all.. because thedio
will keep rolling betweenonRequest
andonError
's try block
You mean if I use the same instance in the onError
callback, it doesn't matter to use try-catch or not because it doesn't reach to that catch block if it fails. Isn't that the problem?
And if I use the same instance in the onError
callback, that dio
should not or cannot throw an Exception because if it does, it will keep rolling between onRequest
and onError
's try block?
Should I call retried original request with in try-catch block or not?
This depends on your code style. I sometimes use the try-catch block to handle specific status codes like 401, 403, 500, and so on. Or handling on 'Presentation Layer' like using Provider, BLoC, or RiverPod.
but if I use dio
(different instances) in the onError
, and it throws an Exception without try-catch
block or catchError
, it will cause Unhandled exception
. Is this expected?
class ErrorInterceptor extends QueuedInterceptor {
final Dio dio;
final Dio dio2;
ErrorInterceptor(this.dio, this.dio2);
@override
Future<void> onError(
DioException err, ErrorInterceptorHandler handler) async {
print('onError is called');
try {
// Without try-catch, it will throw unhandled exception
await dio2.fetch(err.requestOptions);
} catch (e) {
print('onError is called again');
}
handler.next(err);
}
}
void main() async {
var dio = Dio();
var dio2 = Dio();
// Add the custom interceptor
dio.interceptors.addAll([
ErrorInterceptor(dio, dio2),
]);
// Making a GET request
try {
print('Making a GET request...');
Response response =
await dio.get('https://example.com/this-does-not-exist');
print(response.data);
} catch (e) {
print("Final error: $e");
}
}
Really appreciate your assistance!
from dio.
You mean if I use the same instance in the onError callback, it doesn't matter to use try-catch or not because it doesn't reach to that catch block if it fails. Isn't that the problem?
And if I use the same instance in the onError callback, that dio should not or cannot throw an Exception because if it does, it will keep rolling between onRequest and onError's try block?
Yes, it create a cycle like this.
dio (onRequest) → Requested → Error → dio (onError) → dio (onRequest) → Requested → Error → dio (onError) → ...
Isn't that the problem?
the actual outputs is just like as what you added as interceptors.addAll()
but if I use dio(different instances) in the onError, and it throws an Exception without try-catch block or catchError, it will cause Unhandled exception. Is this expected?
Yes, 'onError is called again'
will be printed as you expected 👍
Control with handler's method
next
resolve
reject
that might be helpful
from dio.
I updated example/lib/queued_interceptor_crsftoken.dart here. It seems to be more clear than before like handling errors and queued interceptors.
from dio.
@seunghwanly, thanks for the detailed explanation and updated example.
I have a question about your example, I don't see a case in onError for an automatic retry with a new token, if I wanted to add that, could I just create a new dio in onError and use that like tokenDio?
/// Add `onError` interceptor to request new CSRF token
dio.interceptors.add(
QueuedInterceptorsWrapper(
/// Request new CSRF token
/// if the response status code is `401`
onError: (error, handler) async {
log('Error Detected: ${error.message}');
if (error.response == null) return handler.next(error);
if (error.response?.statusCode == 401) {
try {
final tokenDio = Dio(
BaseOptions(baseUrl: error.requestOptions.baseUrl),
);
/// Generate CSRF token
///
/// This is a MOCK REQUEST to generate a CSRF token.
/// In a real-world scenario, this should be generated by the server.
final result = await tokenDio.post(
'/response-headers',
queryParameters: {
_headerKey: '94d6d1ca-fa06-468f-a25c-2f769d04c26c',
},
);
if (result.statusCode == null || result.statusCode! ~/ 100 != 2) {
throw DioException(requestOptions: result.requestOptions);
}
final updatedToken = result.headers.value(_headerKey);
if (updatedToken == null) throw ArgumentError.notNull(_headerKey);
cachedCSRFToken = updatedToken;
// Can I do like this? or is there better way?
final retryDio = Dio(
BaseOptions(baseUrl: error.requestOptions.baseUrl),
);
final requestOptions = err.requestOptions;
requestOptions.headers['token'] = '$updatedToken';
final res = retryDio.fetch(requestOptions);
return handler.resolve(res);
} on DioException catch (e) {
return handler.reject(e);
}
}
},
),
);
from dio.
@AlexV525
I updated example/lib/queued_interceptor_crsftoken.dart here. It seems to be more clear than before like handling errors and queued interceptors.
Outputs@seunghwanly Hi sorry for missing the thread. Could you submit the pull request?
Thanks, I opened #2128
from dio.
Related Issues (20)
- FormData and List of Int not working as expected. HOT 2
- flutter dynamic coockies management HOT 1
- post请求超时无反应 HOT 1
- Error Dio flutter web HOT 1
- upload file send timeout
- Header is out of order HOT 3
- `ResponseType.stream` is not working on web. HOT 1
- [🔔 Dio] sendTimeout cannot be used without a request body to send HOT 2
- `Transformer.isJsonMimeType` throws format exceptions without caught
- onError is not returning any error HOT 3
- Error when uploading image using MultipartFile.fromBytes in version 5.4.3+1 HOT 1
- 为什么dio的fromMap会将MultipartFile自动放入files字段中 HOT 1
- Error: The method 'debugLog' isn't defined for the class 'BrowserHttpClientAdapter'. HOT 1
- Version 5.5.0 brakes the web build HOT 1
- Is it now possible to use DIO / dio_web_adapter with Web/WASM? HOT 37
- Dio 5.5 broke compilation for WASM HOT 6
- ResponseType.stream returns responce all at once on Web HOT 1
- Date header not parsed correctly
- set proxy for BrowserHttpClientAdapter HOT 1
- Dio fetch can't catch error HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dio.