I'm trying to add dio_cache_interceptor
to my Flutter app. Here are the versions I'm using:
dio: ^5.6.0
dio_cache_interceptor: ^3.5.0
However, when I fire a request, the request is always sent to the webserver, the cache never seems to intercept.
What I've tried or checked:
The response's status code is 200
I tried playing around with the CacheOptions.keyBuilder
, but after all, the keys generated for the requests are always the same
I checked my response headers, they're as following:
(The API is mine too, so I could add headers)
Tried reordering the interceptors, since the execution is in the order of addition (hence, the cache interceptor should be first, right?)
I also have the http: ^1.2.1
package installed, but I'm not using it in this file.
I read the Dio Cache Interceptor Reference, but couldn't find anything else.
I wouldn't know where to look next and spent a whole day now. If anybody could point me in the right direction, I'd highly appreciate it.
Here's my code, I stripped out the unneccessary parts:
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
class WebAPIProvider {
late final Dio dio;
late final CacheOptions cacheOptions;
/// WebAPIProvider Constructor
WebAPIProvider() {
// Set cache options
cacheOptions = CacheOptions(
store: MemCacheStore(),
policy: CachePolicy.request,
hitCacheOnErrorExcept: [403],
maxStale: const Duration(days: 7),
);
// Set base options for every request and add interceptors
dio = Dio(
BaseOptions(
baseUrl: 'https://my.domain.com/webapi/v1',
connectTimeout: const Duration(seconds: 7),
receiveTimeout: const Duration(seconds: 4),
responseType: ResponseType.json,
),
)..interceptors.addAll([
DioCacheInterceptor(
options: cacheOptions,
),
InterceptorsWrapper(
onRequest: onDioRequest,
onResponse: onDioResponse,
onError: onDioError,
),
]);
}
/// Fired before every Dio request
///
/// @Stackoverflow: This adds the accessToken (and other stuff) to the header
FutureOr<void> onDioRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
// Set contentType
options.headers["contentType"] = "application/json";
// Set accessToken
options.headers["accessToken"] = "access-token-here";
// Continue
return handler.next(options);
}
/// Fired at every response Dio receives
///
/// @Stackoverflow: Using this for logging the reponse
FutureOr<void> onDioResponse(
Response response,
ResponseInterceptorHandler handler,
) async {
// Some logging here...
// Continue
return handler.next(response);
}
/// Fired at any error during the request
///
/// @Stackoverflow: Using this for logging the error and resolve with an "empty" dataset
FutureOr<void> onDioError(
DioException exception,
handler,
) async {
// Continue with empty response
return handler.resolve(Response(
extra: {"exceptionType": exception.type},
requestOptions: exception.requestOptions,
));
}
/// 🌐 Invokes the API [endpoint] with optional [requestHeaders] and [queryParameters].
///
/// @Stackoverflow: This is the method I'm invoking, i.e. data = api.get('/my/endpoint')
Future<Response> get(
String endpoint, [
Map<String, String>? requestHeaders,
Map<String, dynamic>? queryParameters,
]) async {
// Send request
Response<dynamic> response = await dio.get(
endpoint,
queryParameters: queryParameters,
options: Options(
headers: requestHeaders,
),
);
// Here I would convert it into a specific type, matching my API
return response;
}
}
Greetings, Boris
Addendum:
I tried also making the function onDioRequest()
synchronous. It was async, because I was reading the access token from the secure storage. However, my response always contains the extra: {@cache_key@: always-same-key, @fromNetwork@: true
.
I finally figured it out. I initialized the above class within my aaaRepository
's constructor. Now whenever I visited page aaa, the repository would be created and initialize above class anew. If I would switch to page bbb and back, the class would be re-initialized and with it it's cache. So Dio would actually cache, just not long enough.
The solution was to use a repository provider on the main()
level, so it would persist trough the app.