HttpClient不能正确缓存响应 [英] Httpclient doesn't correctly caches responses

查看:75
本文介绍了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天全站免登陆