改造+ OkHTTP-响应缓存不起作用 [英] Retrofit + OkHTTP - response cache not working

查看:280
本文介绍了改造+ OkHTTP-响应缓存不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道有很多类似的问题,但是我都看过了,没有一个真正有用。

I know there has been a lot of similar questions, but I have read them all and none of them really helped.

所以,这是我的问题:

我正在使用翻新+ okhttp从API提取一些数据,我想将其缓存。不幸的是,我没有对该API服务器的管理员访问权限,因此无法修改该服务器返回的标头。 (当前,服务器返回Cache-Control:私有的)。

I am using retrofit + okhttp to fetch some data from API and I'd like to cache them. Unfortunately, I don't have admin access to the API server so I can't modify headers returned by the server. (currently, server returns Cache-control: private)

所以我决定使用okhttp标头欺骗来插入适当的缓存标头。可悲的是,无论我做什么,缓存似乎都不起作用。

So I decided to use okhttp header spoofing to insert appropriate cache headers. Sadly, no matter what I do, caching doesn't seem to work.

我初始化api服务是这样的:

I initialise the api service like this:

int cacheSize = 10 * 1024 * 1024; // 10 MiB
File cacheFile = new File(context.getCacheDir(), "thumbs");
final Cache cache = new Cache(cacheFile, cacheSize);

OkHttpClient client = new OkHttpClient();
client.setCache(cache);
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());
        return originalResponse.newBuilder()
                .removeHeader("Access-Control-Allow-Origin")
                .removeHeader("Vary")
                .removeHeader("Age")
                .removeHeader("Via")
                .removeHeader("C3-Request")
                .removeHeader("C3-Domain")
                .removeHeader("C3-Date")
                .removeHeader("C3-Hostname")
                .removeHeader("C3-Cache-Control")
                .removeHeader("X-Varnish-back")
                .removeHeader("X-Varnish")
                .removeHeader("X-Cache")
                .removeHeader("X-Cache-Hit")
                .removeHeader("X-Varnish-front")
                .removeHeader("Connection")
                .removeHeader("Accept-Ranges")
                .removeHeader("Transfer-Encoding")
                .header("Cache-Control", "public, max-age=60")
              //.header("Expires", "Mon, 27 Apr 2015 08:15:14 GMT")
                .build();
    }
});

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(API_ROOT)
    .setLogLevel(RestAdapter.LogLevel.HEADERS_AND_ARGS)
    .setClient(new OkClient(client))
    .setConverter(new SimpleXMLConverter(false))
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            if (Network.isConnected(context)) {
                int maxAge = 60; // read from cache for 2 minutes
                request.addHeader("Cache-Control", "public, max-age=" + maxAge);
            } else {
                int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
                request.addHeader("Cache-Control",
                    "public, only-if-cached, max-stale=" + maxStale);
            }
        }
    })
    .build();
api = restAdapter.create(ApiService.class);

当然,不必删除所有这些标头,但我想使响应变得干净

Of course, it's not necessary to remove all these headers, but I wanted to make the response as clean as possible to rule out some interference from these extra headers.

如您所见,我还尝试欺骗Expires和Date标头(我尝试删除它们,将它们设置为两者之间确实存在最大年龄差异,并且还将Expires设置为遥远的未来)。我还尝试了各种Cache-control值,但是没有运气。

As you can see, I tried to also spoof Expires and Date header (I tried removing them, setting them so that there is exactly max-age differnece between them and also setting Expires far into future). I also experimented with various Cache-control values, but no luck.

我确保cacheFile存在,isDirectory并且可由应用程序写入。

I made sure the cacheFile exists, isDirectory and is writeable by the application.

这些是通过改型直接记录的请求和响应标头:

These are the request and response headers as logged directly by retrofit:

Request:
Cache-Control: public, max-age=60
---> END HTTP (no body)

Response:
Date: Mon, 27 Apr 2015 08:41:10 GMT
Server: Apache/2.2.22 (Ubuntu)
Expires: Mon, 27 Apr 2015 08:46:10 GMT
Content-Type: text/xml; charset=UTF-8
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1430124070000
OkHttp-Received-Millis: 1430124070040
Cache-Control: public, max-age=60
<--- END HTTP (-1-byte body)
<--- BODY: ...

最后,出现了一个奇怪的事件:在某个时刻,缓存工作了几分钟。我得到了合理的点击计数,即使脱机请求也返回了缓存的值。 (这是在使用此处发布的确切设置时发生的),但是当我重新启动该应用程序时,一切恢复为正常(命中率恒定为0)。

And, finally one strange incident: At some point, the cache worked for a few minutes. I was getting reasonable hit counts, even offline requests returned cached values. (It happened while using the exact setting posted here) But when I restarted the app, everything was back to "normal" (constant hit count 0).

如果有人不知道这里可能是什么问题,我真的很高兴得到任何帮助:)

Co if anyone has any idea what could be the problem here, I'd be really glad for any help :)

推荐答案

使用networkInterceptors()而不是interceptors()。将其与您删除所有与缓存相关的标头的策略结合使用将起作用。

Use networkInterceptors() instead of interceptors(). That in combination with your strategy of removing any headers that are somewhat related to caching will work. That's the short answer.

当您使用拦截器更改标头时,在调用CacheStrategy.isCacheable()之前,它不会进行任何调整。值得一看的是CacheStrategy和CacheControl类,以了解OKHttp如何处理与缓存相关的标头。在 http:// www上进行ctrl + f缓存也是值得的。 w3.org/Protocols/rfc2616/rfc2616-sec14.html

When you use interceptors to change headers it does not make any adjustments before CacheStrategy.isCacheable() is called. It's worthwhile to look at the CacheStrategy and CacheControl classes to see how OKHttp handles cache-related headers. It's also worthwhile to do ctrl+f "cache" on http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

我不确定networkInterceptors()和interceptors()文档是否不清楚或如果有错误。一经研究,我将更新此答案。

I am not sure if the networkInterceptors() and interceptors() documentation is just unclear or if there is a bug. Once I look into that more, I will update this answer.

这篇关于改造+ OkHTTP-响应缓存不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆