Httpclient 没有正确缓存响应 [英] Httpclient doesn't correctly caches responses

查看:29
本文介绍了Httpclient 没有正确缓存响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 apache httpclient 加载带有缓存的图像.请求后文件被保存,但在重复相同的请求后,它开始再次下载并将新文件保存为缓存.所以缓存的图像不会被重用.并且不删.

I'm trying to use apache httpclient to load images with caching. After request the file is saved but after repeating same request it begins to download again and new file saved as cache. So cached images not reused. And not deleting.

文件名仅因散列而不同
1389449846612.0000000000000001-3f1e8b88.localhost.-images-goods-212250-7841874.jpg
1389449952782.0000000000000001-5720e341.localhost.-images-goods-212250-7841874.jpg

File names differ only by hash
1389449846612.0000000000000001-3f1e8b88.localhost.-images-goods-212250-7841874.jpg
1389449952782.0000000000000001-5720e341.localhost.-images-goods-212250-7841874.jpg

我希望,该图像将被加载一次,并且即使在没有连接到互联网的情况下也能显示缓存的图像.

I want, that image will be loaded once and be able to show cached image even when there is no connection to internet.

这是我的代码

RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(30000)
                .setSocketTimeout(30000)
                .setProxy(getProxy())
                .build();

CacheConfig cacheConfig = CacheConfig.custom()
        .build();

CloseableHttpClient client = CachingHttpClientBuilder.create()
        .setCacheDir(new File("/sdcard/Android/data/com.myapp/cache/"))
        .setCacheConfig(cacheConfig)
        .setDefaultRequestConfig(config)
        .build();

HttpGet request = new HttpGet(imageUri);
HttpCacheContext context = HttpCacheContext.create();
CloseableHttpResponse response = client.execute(request, context);

这是图片响应头

Cache-Control:max-age=604800
Connection:keep-alive
Content-Length:449512
Content-Type:image/jpeg
Date:Sat, 11 Jan 2014 15:03:21 GMT
Expires:Sat, 18 Jan 2014 15:03:21 GMT
Last-Modified:Tue, 12 Jul 2011 19:40:44 GMT

推荐答案

第一个问题是我每次下载前都创建了新的 httpclient,所以每次都创建了 HttpCacheStorage 的新实例,这就是为什么文件有不同的名称.
其次,默认 HttpCacheStorage 仅在 LinkedHashMap 中存储下载数据的信息,因此在每次新启动应用程序后,cacheStorage 对上次启动时缓存的数据一无所知.
解决方案是创建自己的 HttpCacheStorage,它会将缓存的数据保存到文件系统,并在可以从缓存中获取响应时从文件中获取数据.

First problem is that i'm created new httpclient every time before download, so every time was created new instance of HttpCacheStorage, this is why files had different names.
Second, default HttpCacheStorage stores info of downloaded data just in LinkedHashMap so after every new launch of app cacheStorage don't know anything about cached data in previous launch.
Solutions was to create own HttpCacheStorage, wich will save cached data to file system and will get data from files when response can be got from cache.

我刚刚在 CachingHttpClientBuilder 中添加了一行 - setHttpCacheStorage

I just added one line to CachingHttpClientBuilder - setHttpCacheStorage

CachingHttpClientBuilder.create()
                        .setCacheConfig(cacheConfig)
                        .setHttpCacheStorage(new ImagesCacheStorage(cacheConfig, cacheDir))
                        .setDefaultRequestConfig(config)
                        .build();

并创建了新的类 FileCacheStorage

and created new class FileCacheStorage

import myapp.org.apache.http.client.cache.HttpCacheEntry;
import myapp.org.apache.http.client.cache.HttpCacheUpdateCallback;
import myapp.org.apache.http.impl.client.cache.CacheConfig;
import myapp.org.apache.http.impl.client.cache.ManagedHttpCacheStorage;

public class FileCacheStorage extends ManagedHttpCacheStorage {

    private File mCacheDir;

    public FileCacheStorage(final CacheConfig config, File cacheDir) {
        super(config);
        mCacheDir = cacheDir;
    }

    @Override
    public HttpCacheEntry getEntry(final String url) throws IOException {
        HttpCacheEntry entry = super.getEntry(url);
        if (entry == null) {
            entry = loadCacheEnrty(url);
        }
        return entry;
    }

    @Override
    public void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
        super.putEntry(url, entry);
        saveCacheEntry(url, entry);
    }

    @Override
    public void removeEntry(final String url) throws IOException {
        super.removeEntry(url);
        File cache = getCacheFile(url);
        if (cache != null && cache.exists()) {
            cache.delete();
        }
    }

    @Override
    public void updateEntry(
            final String url,
            final HttpCacheUpdateCallback callback) throws IOException {
        super.updateEntry(url, callback);
        HttpCacheEntry entry = loadCacheEnrty(url);
        if (entry != null) {
            callback.update(entry);
        }
    }

    private void saveCacheEntry(String url, HttpCacheEntry entry) {
        ObjectOutputStream stream = null;
        try {
            File cache = getCacheFile(url);
            stream = new ObjectOutputStream(new FileOutputStream(cache));
            stream.writeObject(entry);
            stream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private HttpCacheEntry loadCacheEnrty(String url) {
        HttpCacheEntry entry = null;
        File cache = getCacheFile(url);
        if (cache != null && cache.exists()) {
            synchronized (this) {
                ObjectInputStream stream = null;
                try {
                    stream = new ObjectInputStream(new FileInputStream(cache));
                    entry = (HttpCacheEntry) stream.readObject();
                    stream.close();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (StreamCorruptedException e) {
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return entry;
    }

    private File getCacheFile(String url) {
        return new File(mCacheDir, MD5.getHash(url));
    }

}

如您所见,Apache 类具有前缀为 myapp 的包名称.尝试使用原始 jar 文件时出现错误,我认为这是因为 Android 中已经存在许多类.所以我结合了来自 apache 的几个 jar 文件,并用它们制作了一个带有该前缀的 jar.如果有人有更好的解决方案,请告诉我.希望对某人有所帮助.

As you can see Apache classes have package name with prefix myapp. I got errors when tryed to use origin jar files, I think it's because many classes are already present in Android. So I combined few jar files from apache and made from them one jar with that prefix. If someone have a better solution let me know. Hope it help someone.

这篇关于Httpclient 没有正确缓存响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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