首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >改进ETAG和缓存

改进ETAG和缓存
EN

Stack Overflow用户
提问于 2014-12-19 08:10:11
回答 3查看 10.1K关注 0票数 16

对于如何将缓存和ETAG/If-None-Match支持添加到Retrofit+OkHttp,是否有正确的解释?我很难在两个项目上添加Etag支持,一开始我怀疑headers可能有问题,另一个项目的所有设置都正确,缓存仍然不能像预期的那样工作。

以下是我努力使它发挥作用的努力。结果表明,缓存似乎在应用程序的同一个实例中工作,但一旦我重新启动,所有的东西都会重新加载很长时间。而且,在我的日志中,我没有看到If-None-Match被添加到请求中,所以我假设服务器不知道ETag,并且仍然完全重新计算响应。

下面是一些代码示例:

代码语言:javascript
复制
public class RetrofitHttpClient extends UrlConnectionClient
{

    private OkUrlFactory generateDefaultOkUrlFactory()
    {
        OkHttpClient client = new com.squareup.okhttp.OkHttpClient();

        try
        {
            Cache responseCache = new Cache(baseContext.getCacheDir(), SIZE_OF_CACHE);
            client.setCache(responseCache);
        }
        catch (Exception e)
        {
            Logger.log(this, e, "Unable to set http cache");
        }

        client.setConnectTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS);
        client.setReadTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
        return new OkUrlFactory(client);
    }

    private final OkUrlFactory factory;

    public RetrofitHttpClient()
    {
        factory = generateDefaultOkUrlFactory();
    }

    @Override
    protected HttpURLConnection openConnection(retrofit.client.Request request) throws IOException
    {
        return factory.open(new URL(request.getUrl()));
    }
}

然后使用完整日志级别和自定义标记创建Rest适配器:

代码语言:javascript
复制
restAdapter = new RestAdapter.Builder()
        .setClient(new RetrofitHttpClient())
        .setEndpoint(Config.BASE_URL)
        .setRequestInterceptor(new SignatureSetter())
        .setConverter(new JacksonConverter(JsonHelper.getObjectMapper()))
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .setLog(new AndroidLog("=NETWORK="))
        .build();

我有一个很长的要求在应用程序的第一个屏幕上进行测试。当我打开应用程序-它需要7秒来完成请求。如果我暂停并继续这个应用程序-相同的请求需要250毫秒,显然击中缓存。如果我完全关闭应用程序并重新启动-它再次需要7秒。

UPDATE:正如所建议的那样,我使用了一个定制的Retrofit构建并附加了一个LoggingInterceptor。这是我得到的。

代码语言:javascript
复制
Received response for *** in 449,3ms
Date: Wed, 07 Jan 2015 09:02:23 GMT
Server: Apache
X-Powered-By: PHP/5.4.31
Access-Control-Allow-Credentials: true
Pragma:
Cache-Control: public, max-age=3600
X-Frame-Options: SAMEORIGIN
Etag: "hLxLRYztkinJAB453nRV7ncBSuU=-gzip"
Last-Modified: Wed, 24 Dec 2014 13:09:04 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1420621288104
OkHttp-Received-Millis: 1420621288554


Sending request **** on Connection{****:80, proxy=DIRECT@ hostAddress=**** cipherSuite=none protocol=http/1.1}
Accept: application/json;
Host: ****
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/2.2.0

Response is equal to described above

如您所见,在下一个请求中不存在If-None-Match头。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-05-05 15:12:43

我看到这个问题一直在引起人们的注意,一旦没有真正的答案,我就能从中找到答案--我正在对这个话题进行调查,暂时结束这个话题。

调查的最终结果以及在GitHub上的修改和okhttp线程中的一些讨论的结果是,据推测,OkHttp中存在一个问题,可以阻止为传出请求设置If- for匹配标记。

这个问题应该在OkHttp 2.3中解决,我在这里使用“假设”,因为我还没有测试它是否真正有效。测试是很困难的,因为我使用的是Retrofit,为了使用新版本的OkHttp并添加一些新的拦截器支持来调试由OkHttp设置的所有标头,必须更新Retrofit本身。相关线程在这里:https://github.com/square/okhttp/issues/831

我不确定在那之后是否更新了Retrofit。希望是这样,所以很有可能问题已经解决了,Etag应该能正常工作--只要确保您有Retrofit和OkHttp的最新版本。

一旦我有时间,我将试着亲自测试所有的东西。

票数 6
EN

Stack Overflow用户

发布于 2015-01-03 19:14:17

使用OkHttp拦截器将帮助您诊断进出应用程序的标头。拦截器文档给出了一个拦截器的代码示例,该拦截器记录网络上的请求和响应头。你可以按原样用这个。

代码语言:javascript
复制
class LoggingInterceptor implements Interceptor {
  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    long t1 = System.nanoTime();
    logger.info(String.format("Sending request %s on %s%n%s",
        request.url(), chain.connection(), request.headers()));

    Response response = chain.proceed(request);

    long t2 = System.nanoTime();
    logger.info(String.format("Received response for %s in %.1fms%n%s",
        response.request().url(), (t2 - t1) / 1e6d, response.headers()));

    return response;
  }
}

要将其连接到Retrofit,您需要获得Retrofit的预发布快照。截至2015年1月,目前版本的改装不参与OkHttp的拦截器。不久将发布一个版本,但它还没有准备好。

票数 1
EN

Stack Overflow用户

发布于 2014-12-30 14:35:53

我也遇到了类似的问题:即使服务器发送相同的ETAG,OkHttp也没有命中缓存。

我的问题是SIZE_OF_CACHE。我在定义一个很小的尺寸。

尝试增加它(比如10 * 1024 * 1024对我有用),你也可以探索/data/data//file/cache,看看那里是否真的有存储的东西。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27561992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档