hurshi / dio-http-cache Goto Github PK
View Code? Open in Web Editor NEWhttp cache lib for Flutter dio like RxCache
License: Apache License 2.0
http cache lib for Flutter dio like RxCache
License: Apache License 2.0
Hi, I see CacheConfig.baseUrl
as a parameter, but there's no documentation on what it's for. Could you explain the purpose of this parameter?
Flutter Web will be stable in the coming month.
It would be very nice to have WEB support for our current app with minimum changes.
My current application is using http-cache and due to sqlite dependency, the app can not run on WEB.
A solution will be to use sembast plugin (WEB ready).
First of all thanks for your amazing package!
I see in the README that you need to enable and interceptor with a BaseUrl.
How this exactly works? is mandatory? I mean i can only set the CacheManager with no baseUrl?
All these questions arose because i have a case when I want to cache some requests but others don't, how do i should do that? set in the request maxAge to 0?
1、默认的获取数据的逻辑
2、本地和网络策略实现的建议
支持缓存图片吗,将来会支持吗
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: DioError [DioErrorType.DEFAULT]: NoSuchMethodError: The method 'trim' was called on null.
Receiver: null
Tried calling: trim()
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 Headers.set (package:dio/src/headers.dart:61:27)
#2 Headers.add (package:dio/src/headers.dart:49:29)
#3 DioCacheManager._buildResponse. (package:dio_http_cache/src/manager_dio.dart:65:47)
#4 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
#5 DioCacheManager._buildResponse (package:dio_http_cache/src/manager_dio.dart:65:21)
#6 DioCacheManager._onError (package:dio_http_cache/src/manager_dio.dart:58:16)
#7 InterceptorsWrapper.onError (package:dio/src/interceptor.dart:125:14)
#8 DioMixin._request._errorInterceptorWrapper. (package:dio/src/dio.dart:846:40)
#9 _rootRunUn<…>
hope to add custom store and data view interface
It seems that the headers of network responses are discarded, and when a response is built from the cache it uses the request headers instead.
In my use case the response headers for a certain request contain crucial link information for paginated data. For example, I make a request to an API that returns 100 items in the first 'page', and the headers contain a link to the next 'page' that also returns 100 items and also has link headers for the subsequent page, and so forth. However, if the response is a cached response then these headers will be missing, which means that I cannot access more than a single page of data even if the subsequent pages have been previously cached.
Preserving the original headers and restoring them in the cached response would solve this issue.
Hi,
When we use dio , we can set options as :
Dio dio = Dio();
Options options = Options(
headers: {
'Accept-Language': 'en',
'Authorization': 'Token 12345',
},
);
Response response = await Dio().get("http://www.google.com", options: options);
And when use dio-http-cache. we set options as:
DioCacheManager dioCacheManager = DioCacheManager(CacheConfig());
Options cacheOptions = buildCacheOptions(Duration(days: 7));
Dio dio = Dio();
dio.interceptors.add(dioCacheManager.interceptor);
Response response = await Dio().get("http://www.google.com", options: cacheOptions);
Now how we can use theses options together?
如题
如果 服务端不支持缓存,该怎么做,是像okHttp一样 在responce中添加 cache-Controll等header信息吗
Any plan to provide support for Flutter WEB ?
Thank you @hurshi for the awesome package! I got a few questions, maybe you can add the answers in the future to README?
It would be nice to be able to pass in your own version of CacheStore so that users are able to implement using different databases, such as Hive or Moor.
Hello i'm beginner
Why when closing an app cache cleared.
var _dio = Dio();
var _dioCacheManager = new DioCacheManager(CacheConfig(baseUrl: url));
_dio.interceptors.add(_dioCacheManager.interceptor);
var response = await _dio.post("${url}",
data: params,
options: buildCacheOptions(
Duration(days: 3),
maxStale: Duration(days: 7),
));
DOC: dio-http-cache uses url as key
.
Letting the user define custom keys for caching would enable users to share cache between requests.
Such a feature is interesting in the following example:
http://example.com/a/b
http://example.com/a/b?timestamp=1566563506431
http://example.com/a/b?timestamp=1566563506433
The API needs a timestamp GET parameter that cannot be shared between requests, be we would like to save them as ONE request in sqflite. (for MaxStale
fallback)
The above case can also be solved by providing queryParameters
at the buildCacheOptions
level, where they could be ignore by the hash method.
作者你好:
在我们项目中遇到了需要按照缓存文件数量来清理缓存的需求,或者说按照缓存磁盘大小来清理。当达到文件数量或者磁盘空间时,把老的数据清理掉~肯请作者支持下。 mua.. 😄
When relying on response headers for max cache time, i.e. no manually set max age, the cache-control
header is not properly parsed, causing the whole caching to fail.
To reproduce, set up a dio get with options: buildServiceCacheOptions()
. The request will never be served from cache.
I tried to debug the library and found that the cache-control
header value is noty properly parsed in_tryParseHead
. Currently this reads:
parameters = HeaderValue.parse(cacheControl,
parameterSeparator: ",", valueSeparator: "=")
But the HeaderValue.parse
method expects the header name to be present in the given String, so it should be:
parameters = HeaderValue.parse(HttpHeaders.cacheControlHeader + ": " + cacheControl,
parameterSeparator: ",", valueSeparator: "=")
切换网络以后,请求接口数据变化,但是只能请求到旧的数据,而且response的code和status都是null
Hi,
Just implemented the cache plugin and it works perfectly on Android Emulator, returns data from cache when Airplane mode is on. But when the app is deployed on a physical device, either in debug or release mode, the cache doesn't work at all. No error messages can be seen in the debug log as well. What am I missing here?
一个搜索功能的接口,通过http状态码判断请求状态,当状态码为200代表正常数据返回,204的时候代表没有数据,缓存之后原来是204的数据再次请求命中缓存却变成了200
Hi , thanks for the library.I wanted to ask if its possible to know if the response is cached data or not.This way i will be able to notify UI that the data is cached and may not be updated.Thanks
Hello, I'm validating the status code and it's returned as null by default, maybe it would be good to return 200 by default?
Hello, @hurshi I'm using this package and it's awesome! What do you think, right now we can delete the resource via key and subkey but if we want to delete an entire resource what to do?
E.g, I have a https://resource.com?page=1 and 100 pages of it but I need to refresh the whole resource, not only a particular page. From my perspective, I see two solutions: add key as the path and subkey as the query by default or add a wildcard delete that will take only the URL path into consideration.
Have a nice day ✨
可以通过_dioCacheManager 获取数据库key,Data 嘛?
Example:
rest.interceptors.add(
DioCacheManager(
CacheConfig(
baseUrl: rest.options.baseUrl,
defaultMaxAge: Duration(minutes: 5),
),
).interceptor,
);
defaultMaxAge is NOT used in case server does not return any max-age in response.
The bug is probably in:
Future<bool> _pushToCache(Response response) {
RequestOptions options = response.request;
Duration maxAge = options.extra[DIO_CACHE_KEY_MAX_AGE];
Duration maxStale = options.extra[DIO_CACHE_KEY_MAX_STALE];
if (null == maxAge) {
_tryParseHead(response, maxStale, (_maxAge, _maxStale) {
maxAge = _maxAge;
maxStale = _maxStale;
});
}
// FIX
if (null == maxAge) {
maxAge = _manager?._config.defaultMaxAge;
maxStale = _manager?._config.defaultMaxStale;
}
// End of FIX
if (null == maxAge) return Future.value(false);
See also comments in #12
Where is the disk cache saved? If it's saved to a temp directory how can one change that to a permanent directory?
I've been diggling through the codebase, and while I see MaxMemoryCacheCount
option, there is nothing I'm aware of which would limit the on-disk cache.
How do we ensure the SQLite cache doesn't eat up too much space on client device ? Is there any way of approaching this, currently ?
If not, I'd be happy to implement this!
1、目前我同一个path 有一个GET请求 一个是PUT请求 发现两者缓存会出现混乱 GET请求的时候会加载到PUT请求的缓存 虽然目前通过认为设置subKey避免了 但觉得可以优化一下
2、希望可以设置可以缓存的请求类型 ,或者缓存只针对GET请求 对于非GET请求 比如POST/PUT等操作类请求默认不缓存 或者可以设置为不缓存
你在插入缓存的时候key值使用了_getPrimaryKeyFromOptions转换,清除的时候并没有使用_getPrimaryKeyFromOptions转换,导致key值无法匹配,最好在清除的时候也用_getPrimaryKeyFromOptions转换,并且传递options.method。
Can you please detail in the documentation how is managed the case when no network is available ? Is there an error or the data is returned by the cache ?
Hello Hurshi. The memory is not invalidated because it should support "where" clause. Let me elaborate
mapCache.invalidate("${key}${subKey ?? ""}");
this line deletes only one record with the specified key and subkey, but what we actually want to achieve is to delete all the occurrences where key is present. So, it clears the disk cache, but the memory still stays the same.
There are multiple cache control headers sent as part of an HTTP response. It would be nice if cache expiration was controlled by those headers by default, and then override using the existing mechanisms.
这个插件挺好,目前dio 3.0已发布,希望能尽快支持,当支持3.0后,我们会将此插件归档到dio文档中。
作者你好:是否支持 http cache,由服务端控制缓存时间及策略;我看demo中都是由客户端控制缓存时间的
Wrapping the options property of a get request with buildCacheOptions in this way:
dio.get( url, options: buildCacheOptions(Duration(days: 7), options: Options(responseType: ResponseType.bytes)) );
The response data property is an String that contains correct data ("[1,23,232...]") but it's not a List of ints ([1,23,232]).
Is that the expected behaviour , or it's a bug?
希望可以在使用了缓存的请求头部增加一个{"dio-http-cache":true}之类的值
I would like to use this option as "defaultConfig"
buildCacheOptions(Duration(days: 7), forceRefresh: true)
I do not see the forceRefresh property in the CacheConfig object ?
Is it possible or do we need to buildCacheOption for each request requiring forceRefresh to true ?
According to the documentation:
Example for maxAge and maxStale #
_dio.post(
"https://www.exmaple.com",
data: {'k': "keyword"},
options:buildCacheOptions(
Duration(days: 3),
maxStale: Duration(days: 7),
)
)
0 ~ 3 days : Return data from cache directly (irrelevant with network).
3 ~ 7 days:
Get data from network first.
If getting data from network succeeds, refresh cache.
If getting data from network fails or no network avaliable, try get data from cache instead of an error.
7 ~ ∞ days: It won't use cache anymore, and the cache will be deleted at the right time.
Yet it is not getting the data from the cache in the 3-7 days range, instead it just throws an error of failed host lookup (Airplane mode was turned on to test this). Any solutions to this?
We have an app that pings multiple APIs, but we need caching for just one of them. Can you add whitelisting?
@hurshi 您好
首先很感谢您开源的网络框架 我看了您的文档 现在有如下疑问:
1、通过拦截器设置的缓存策略是否可以称之为全局缓存策略?也就是设置全局缓存策略后,同一个baseUrl下的所有请求都会采用这一策略进行缓存,所以只有当个别请求需要采用和全局缓存不一致的策略的时候 才需要在请求的时候通过option进行针对性设置;
2、通过拦截器设置缓存策略的baseUrl参数如果为空 是否就代表针对后续的所有请求(不管其baseUrl是什么),该缓存策略都会生效?或者baseUrl 是否支持多个取值?
3、目前通过拦截器设置的缓存策略(全局策略 如果我理解无误的话),是否可以支持指定接口请求类型的缓存过滤(比如,只针对GET进行缓存 排除POST PUT等)
在编码调试中发现,网络断了,未使用缓存中的数据。
查看文档发现,有两种方式设置:
如果这两种方式同时设置,参数如何生效?
// 1. 在请求配置了参数options
Response response = await authHttp.get('/user/followers',
queryParameters: {'page': page, 'per_page': pageSize},
options: buildOptions(forceRefresh))
// 2. method
Options buildOptions(bool forceRefresh) {
return buildCacheOptions(Duration(days: 7), forceRefresh: forceRefresh);
}
// 3. 在拦截器中配置了CacheConfig
DioCacheManager(CacheConfig(
baseUrl: Constants.GITHUB_API_PREFIX,
databaseName: 'Cache',
defaultMaxStale: Duration(days: 10)))
.interceptor,
Hello,
I love your library, it's a really nice plug-and-play addon.
I could not find anything in the docs regarding ETag and If-None-Match HTTP headers. I am using those to diminish network traffic between my app and my back-end.
Are these supported out of the box? If not, I'd be glad to try and implement this feature.
Currently, almost all methods inside cache manager are asynchronous by nature but they are not marked as async, so you cannot await them to make a delete operation before retrieving from the cache.
delete(String key, {String subKey}) {
key = _convertMd5(key);
if (null != subKey) subKey = _convertMd5(subKey);
_memoryCacheStore?.delete(key, subKey: subKey);
_diskCacheStore?.delete(key, subKey: subKey);
}
`Future<List<People>> getDataName() async {
DioCacheManager _dioCacheManager;
_dioCacheManager = DioCacheManager(CacheConfig());
Options _cacheOptions =
buildCacheOptions(Duration(days: 7), forceRefresh: true,);
Dio _dio = Dio();
_dio.interceptors.add(_dioCacheManager.interceptor);
Response response = await _dio.get(
'https://firebasestorage.googleapis.com/v0/b/sample-awka.appspot.com/o/people.json?alt=media',
options: _cacheOptions);
List<People> _persons =
(response.data as List).map((pr) {
print('$pr');
People prt = People.fromJson(pr);
}).toList();
return _persons;
}`
`Provider.of<People>(context).getDataName();`
flutter:
flutter: ╔╣ DioError ║ DioErrorType.DEFAULT
flutter: ║ RangeError (index): Invalid value: Only valid value is 0: 1
flutter: ╚══════════════════════════════════════════════════════════════════════════════════════════
flutter: DioError [DioErrorType.DEFAULT]: RangeError (index): Invalid value: Only valid value is 0: 1
#0 List.[] (dart:core-patch/growable_array.dart:147:60)
#1 RequestOptions.uri (package:dio/src/options.dart:299:29)
#2 DioCacheManager._getPrimaryKeyFromOptions (package:dio_http_cache/src/manager_dio.dart:170:41)
#3 DioCacheManager._pullFromCacheBeforeMaxStale (package:dio_http_cache/src/manager_dio.dart:92:9)
#4 DioCacheManager._onError (package:dio_http_cache/src/manager_dio.dart:64:41)
<asynchronous suspension>
#5 InterceptorsWrapper.onError (package:dio/src/interceptor.dart:125:14)
<asynchronous suspension>
#6 DioMixin._request._errorInterceptorWrapper.<anonymous closure> (package:dio/src/dio.dart:846:40)
<asynchronous suspension>
#7 _rootRunUnary (dart:async/zone.dart:1132:38)
#8 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#9 _FutureListener.handleError (dart:async/future_impl.dart:155:20)
#10 Future._propagateToListeners.handl<…>
flutter: NoSuchMethodError: The getter 'login' was called on null.
Receiver: null
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.