onError method
The callback will be executed on error.
If you want to continue the error , call handler.next
.
If you want to complete the response with some custom data directly,
you can resolve a Response
object with handler.resolve
and other
error interceptor(s) will be skipped.
If you want to complete the response with an error message directly,
you can reject a DioError
object with handler.reject
, and other
error interceptor(s) will be skipped.
Implementation
@override
void onError(DioError err, ErrorInterceptorHandler handler) async {
_dio.interceptors.errorLock.lock();
if (!isRetriable(err)) {
_dio.interceptors.errorLock.unlock();
handler.next(err);
return;
}
try {
_dio.interceptors.requestLock.lock();
final options = err.response?.requestOptions;
final request = err.requestOptions;
final token = await _tokenStore.fromStore();
final refreshToken = token.refreshToken;
if (options == null || refreshToken == null) {
handler.next(err);
return;
}
if (request.headers["Authorization"] != "Bearer ${token.accessToken}") {
// tokens were refreshed by another API request.
print(
"just retry ${options.path} since access token was already refreshed by another request.");
await _dio.fetch(options);
return;
}
final tokenResponse = await _kauthApi.refreshAccessToken(refreshToken);
await _tokenStore.toStore(tokenResponse);
print("retry ${options.path} after refreshing access token.");
await _dio.fetch(options);
return;
} catch (e) {
if (e is KakaoAuthException ||
e is KakaoApiException && e.code == ApiErrorCause.INVALID_TOKEN) {
await _tokenStore.clear();
}
handler.next(err);
return;
} finally {
_dio.interceptors.requestLock.unlock();
_dio.interceptors.errorLock.unlock();
}
}