摘要
采用http缓存能够提高系统性能,减少系统负载。而缓存又分为服务器缓存和客户端缓存。下面是分开进行解释,开发环境如下:
- android端:retrofit,okhttp
- 服务器端:play framework
服务器端
response header设置
返回的response的header需要包含
Cache-Control:max-age=60
Last-Modified : Wed, 05 Aug 2015 02:13:31 GMT
max-age用于告诉客户端,该内容可以缓存60秒。
Last-Modified是数据更新时间,客户端接收到该response后,再次发送请求会携带If-Modified-Since,服务器则判断该数据是否过期。
缓存策略
- 如果header不存在If-Modified-Since,则为第一次访问如果缓存存在数据则从缓存换取,否则重新获取。
- 如果header存在If-Modified-Since,则是非第一次访问,判断If-Modified-Since是否等于Last-Modified,若相等则数据没有更新,返回304。若不等则从缓存获取最新数据。
需要注意的是,由于play自带的CacheAction只能做到将key跟Result对应(一个Controller的方法只能一个key),对于同一方法不同参数无法缓存,所以要另外实现response缓存
android端
Gradle设置
compile ‘com.squareup.retrofit:retrofit:1.9.0’
compile ‘com.squareup.okhttp:okhttp:2.4.0’
compile ‘com.squareup.okhttp:okhttp-urlconnection:2.4.0’
retrofit+okhttp调用代码
static{
File httpCacheDirectory = new File(MyApp.instance.getCacheDir(), "responses");
Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
okHttpClient = new OkHttpClient();
okHttpClient.setCache(cache);
service = new RestAdapter.Builder()
.setEndpoint(SERVER_URL)
.setClient(new OkClient(okHttpClient))
.build()
.create(MyService.class);
}
public static List<GoldListData> getListData(String bank, String goldType){
List<GoldListData> data = service.getListData(bank, goldType);
log.debug("getListData bank={}, goldType={}, ret={}", bank, goldType, data);
return data;
}
public interface MyService{
@GET("/data/{bank}")
List<GoldListData> getListData(@Path("bank") String bank, @Query("goldType") String goldType);
}
缓存策略
- 客户端会根据服务器返回的header进行请求缓存,在max-age规定的时间内,如果多次调用service.getListData(),只在第一次通过网络访问服务器请求数据,其余都在缓存中获取。
- 如果访问服务器返回304,也会继续使用缓存数据。
需要注意的地方
在测试过程中,用wireshark抓包发现,该代码的实际表现跟理论不符合,cache目录下有生成缓存文件,但是在max-age规定的时间内多次调用也发生多次网络请求,后面通过调试代码得知,okhttp缓存算法是通过接收到第一次请求的时间(header里面的Date)跟现在客户端时间做运算再跟max-age比较,因此当客户端时间与服务器时间有一方不准确的时候,则会出现无法从缓存获取数据复用,希望okhttp后面的更新可以解决该问题。