gpt4 book ai didi

android - 在Android中为OkHttp设置缓存的正确方法

转载 作者:IT老高 更新时间:2023-10-28 23:34:04 24 4
gpt4 key购买 nike

我正在尝试为 OkHttp 设置缓存,因此它仅在我第一次尝试从服务器检索响应时向服务器请求,直到过期 header 日期或来自服务器的缓存控制 header 使来自缓存的响应无效。

目前,它缓存响应,但在再次请求资源时不使用它。可能这不是它应该使用的方式。

我正在使用这样的缓存设置 OkHttpClient:

public static Cache createHttpClientCache(Context context) {
try {
File cacheDir = context.getDir("service_api_cache", Context.MODE_PRIVATE);
return new Cache(cacheDir, HTTP_CACHE_SIZE);
} catch (IOException e) {
Log.e(TAG, "Couldn't create http cache because of IO problem.", e);
return null;
}
}

这样使用:

if(cache == null) {
cache = createHttpClientCache(context);
}
sClient.setCache(cache);

这就是我使用 OkHttp 向服务器发出的请求之一,但实际上未能使用缓存:

public static JSONObject getApi(Context context) 
throws IOException, JSONException, InvalidCookie {

HttpCookie sessionCookie = getServerSession(context);
if(sessionCookie == null){
throw new InvalidCookie();
}
String cookieStr = sessionCookie.getName()+"="+sessionCookie.getValue();

Request request = new Request.Builder()
.url(sServiceRootUrl + "/api/"+API_VERSION)
.header("Accept", "application/json")
.header("Cookie", cookieStr)
.build();

Response response = sClient.newCall(request).execute();
if(response.code() == 200){
String charset = getResponseCharset(response);
if(charset == null){
charset = "utf-8";
}
String responseStr = new String(response.body().bytes(), charset);
response.body().close();
return new JSONObject(responseStr);
} else if(response.code() == 401){
throw new InvalidCookie();
} else {
return null;
}

}

如果我到达我指定为 OkHttp 缓存的目录,我可以看到日志文件和其他 4 个包含某些请求响应的文件。此请求(我刚刚粘贴代码的/api 请求)存储在缓存目录中,因此它确实被缓存了,但文件名末尾有一个 .tmp ,就像它没有正确保存到最终文件一样,就像我提出的其他要求一样。

这是请求的服务器响应 header 的样子:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Expires: Sat, 09 Aug 2014 19:36:08 GMT
Cache-Control: max-age=86400, must-revalidate
Last-Modified: Sun, 04 Aug 2013 15:56:04 GMT
Content-Length: 281
Date: Fri, 08 Aug 2014 19:36:08 GMT

这就是 OkHttp 将其存储在缓存中的方式:

{HOST}/api/0.3
GET
0
HTTP/1.1 200 OK
9
Server: Apache-Coyote/1.1
Expires: Sat, 09 Aug 2014 19:36:08 GMT
Cache-Control: max-age=86400, must-revalidate
Last-Modified: Sun, 04 Aug 2013 15:56:04 GMT
Content-Length: 281
Date: Fri, 08 Aug 2014 19:36:08 GMT
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1407526495630
OkHttp-Received-Millis: 1407526495721

OkHttp 创建此文件后,会不断向服务器请求相同的资源。我可以在 Wireshark 中看到这些消息。

我做错了什么?

更新:

这是 Jesse 建议后的服务器响应:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Expires: Thu, 14 Aug 2014 18:06:05 GMT
Last-Modified: Sun, 10 Aug 2014 12:37:06 GMT
Content-Length: 281
Date: Wed, 13 Aug 2014 18:06:05 GMT

更新 2:尝试了代码版本,发现很可能某处存在关于缓存的错误。这是我从 Maven 输出中得到的:

Results :

Failed tests:
CacheTest.conditionalHitUpdatesCache:1653 expected:<[A]> but was:<[B]>

Tests in error:
CallTest.tearDown:86 » IO failed to delete file: C:\Users\Adrian\AppData\Local...

Tests run: 825, Failures: 1, Errors: 1, Skipped: 17

可以在此处查看更完整的日志:https://gist.github.com/16BITBoy/344ea4c22b543f397f53

最佳答案

我刚刚解决了这个问题。当我尝试从源代码使用 OkHttp 时,缓存测试失败,这有点误导。

问题很简单,就是其他请求方法在响应中获取了一个主体,并且最终没有关闭。这就解释了为什么我在缓存中看到了“.tmp”文件,但仍然令人困惑和误导,因为这个请求方法正在消耗并关闭响应的正文。就像缓存编辑器的锁或监视器对所有请求都是全局的,而不是按请求。我虽然不是在阅读代码时,而是在它使用请求的哈希作为键时。

不管怎样,就是这样:D

从现在开始,我会尽量坚持这样的模式……

String respBody = null;
if(response.body() != null) {
respBody = response.body().string();
response.body().close();
}

...在处理响应代码的每个案例之前。这样我就不会错过响应正文的密切联系。

关于android - 在Android中为OkHttp设置缓存的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25211333/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com