okhttp3缓存设置及拦截器的使用

缓存:

服务器支持缓存

如果服务器支持缓存,请求返回的Response会带有这样的Header:Cache-Control, max-age=xxx,这种情况下我们只需要手动给okhttp设置缓存就可以让okhttp自动帮你缓存了。这里的max-age的值代表了缓存在你本地存放的时间。

OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient newClient = okHttpClient.newBuilder()
               .cache(new Cache(mContext.getCacheDir(), 10240*1024))
               .connectTimeout(20, TimeUnit.SECONDS)
               .readTimeout(20, TimeUnit.SECONDS)
               .build();

最简单的使用

//获取sd卡的绝对路径
 File path = Environment.getExternalStorageDirectory().getAbsoluteFile();
//创建缓存文件位置及名称     
File file = new File(path,"/jiyun");
 //创建缓存对象,设置缓存大小    
 Cache cache = new Cache(file,1024*1024*10);
OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient newClient = okHttpClient.newBuilder()
               .cache(cache)
                //连接超时时间
               .connectTimeout(20, TimeUnit.SECONDS)
                //读取超时时间
               .readTimeout(20, TimeUnit.SECONDS)
                //添加应用拦截器
               .addInterceptor(new Interceptor() {
         @Override
         public Response intercept(Chain chain) throws IOException {
             //通过Chain获取请求对象
             Request request = chain.request();
             //通过请求对象添加缓存控制类的属性 
             Request build = request.newBuilder().cacheControl(new 
             //设置缓存本地时间为10 毫秒(maxAge())
             CacheControl.Builder().maxAge(10, TimeUnit.MILLISECONDS).build()).buidl;
             //通过Chain获取响应对象并return
             return  proceed = chain.proceed(request);
          
         }
     });
               

出于安全性的考虑,在Android中我们推荐使用Context.getCacheDir()来作为缓存的存放路径,另外还需要指定缓存的大小就可以创建一个缓存了。如下所示:

注: 在Activity中有 getFileDir() 和 getCacheDir(); 方法可以获得当前的手机自带的存储空间中的当前包文件的路径 
getFileDir() ----- /data/data/cn.xxx.xxx(当前包)/files 
getCacheDir() ----- /data/data/cn.xxx.xxx(当前包)/cache 

OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient newClient = okHttpClient.newBuilder()
                //Android推荐使用getCacheDir()/getFileDir() 来获取手机缓存路径
               .cache(new Cache(mContext.getCacheDir(), 10240*1024))
               .connectTimeout(20, TimeUnit.SECONDS)
               .readTimeout(20, TimeUnit.SECONDS)
               .build();

服务器不支持缓存

如果服务器不支持缓存就可能没有指定这个头部,或者指定的值是如no-store等,但是我们还想在本地使用缓存的话要怎么办呢?这种情况下我们就需要使用Interceptor来重写Respose的头部信息,从而让okhttp支持缓存。
如下所示,我们重写的Response的Cache-Control字段

public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        Response response1 = response.newBuilder()
                .removeHeader("Pragma")
                .removeHeader("Cache-Control")
                //cache for 30 days
                .header("Cache-Control", "max-age=" + 3600 * 24 * 30)
                .build();
        return response1;
    }
}

然后将该Intercepter作为一个NetworkInterceptor加入到okhttpClient中:

OkHttpClient okHttpClient = new OkHttpClient();

OkHttpClient newClient = okHttpClient.newBuilder()
        .addNetworkInterceptor(new CacheInterceptor())
        .cache(cache)
        .connectTimeout(20, TimeUnit.SECONDS)
        .readTimeout(20, TimeUnit.SECONDS)
        .build();

这样服务器不支持缓存的情况下使用缓存。

Cache-Control 为单向指令,即请求中存在的指令,并不意味着响应中存在同样的指令

客户端对请求的处理(请求头设置的Cache-Control):

Web浏览器都有Refresh(刷新)和Reload(重载)按钮,可以强制对浏览器或者代理缓存,进行刷新

Refresh的特性取决于特定的浏览器、文档以及拦截缓存的配置。可以通过下面的指令来强化客户端的缓存配置

Pragma: no-cache

跟Cache-Control: no-cache相同,Pragma: no-cache兼容http 1.0 ,Cache-Control: no-cache是http 1.1提供的。因此,Pragma: no-cache可以应用到http 1.0 和http 1.1,而Cache-Control: no-cache只能应用于http 1.1.

请求中Cache-Control指令
指令 目的
Cache-Control:max-stale=<s> 缓存可随意提供过期文件,如果指定了参数<s> 在这段时间内,文档不能过期
Cache-Control:max-age=<s> 缓存无法返回缓存时间大于<s>秒的文件,这条指令使得缓存更加严格
Cache-Control:no-cache 除非资源进行了再验证,否则客户端不会接受已经缓存的资源
Cache-Control:no-store 缓存尽快从存储器中删除资源痕迹
Cache-Control:only-if-cached 当缓存中有副本文件存在才,客户端才会获取副本

服务器对Cache-Control的配置:

响应的Cache-Control指令
指令 说明
public 所有内容都被缓存
private 仅客户端缓存代理服务器不缓存
no-cache 必须先与代理服务器确认是否更改,然后在在决定使用缓存还是请求
no-store 所有内容都不会被缓存
must-revalidation/proxy-revalidation 如果缓存内容失效,请求必须发送服务器/代理进行验证
max-age=<s> 缓存内容在s秒后失效,仅HTTP1.1可用


对于上述配置浏览器的响应为:

浏览器对于Cache-Control的响应
指令 打开新窗口 原窗口单击Enter按钮 刷新 点击返回按钮
public 缓存页面 缓存页面 重新请求页面 缓存页面
private 重新请求 第一次请求,随后缓存 重新请求页面 缓存页面
no-cache/no-store 重新请求 重新请求 重新请求 缓存页面
must-revalidation/proxy-revalidation 浏览器重新请求 第一次请求,随后缓存 重新请求 缓存页面
max-age=xxx 在XX秒后重新请求 在XX秒后重新请求 重新请求 在xx秒后重新请求
     noCache();//不使用缓存,全部走网络
     noStore();//不使用缓存,也不存储缓存
     onlyIfCached();//只使用缓存
     noTransform();//禁止转码
     maxAge(10, TimeUnit.MILLISECONDS);//指示客户机可以接收生存期不大于指定时间的响应。
     maxStale(10, TimeUnit.SECONDS);//指示客户机可以接收超出超时期间的响应消息
     minFresh(10, TimeUnit.SECONDS);//指示客户机可以接收响应时间小于当前时间加上指定时间的响应。

拦截器的选择
1)应用拦截器
不需要担心中间过程的响应,如重定向和重试.
总是只调用一次,即使HTTP响应是从缓存中获取.
观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
允许短路而不调用 Chain.proceed(),即中止调用.
允许重试,使 Chain.proceed()调用多次.
2)网络拦截器
能够操作中间过程的响应,如重定向和重试.
当网络短路而返回缓存响应时不被调用.
只观察在网络上传输的数据.
携带请求来访问连接.

无论有无网络我们都先获取缓存的数据。

1.先要创建拦截器。

/**
     * 一、无论有无网路都添加缓存。
     * 目前的情况是我们这个要addNetworkInterceptor
     * 这样才有效。经过本人测试(chan)测试有效.
     * 60S后如果没有网络将获取不到数据,显示连接失败
     */
    static Interceptor netInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
          /*String cacheControl = request.header("Cache-Control");
            if (TextUtils.isEmpty(cacheControl)) {
                cacheControl = "public, max-age=60";
            }*/
            int maxAge = 60;
            return response.newBuilder()
                    .removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, max-age=" + maxAge)
                    .build();
        }
    };

2.这样的话就写好了拦截器,然后哦就是把拦截器设置到okhttp里面

 File cacheFile = new File(BaseApp.getInstance().getCacheDir(), "caheData");
        //设置缓存大小
        Cache cache = new Cache(cacheFile, DEFAULT_DIR_CACHE);//google建议放到这里
        OkHttpClient client = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)//连接失败后是否重新连接
                .connectTimeout(15, TimeUnit.SECONDS)//超时时间15S
                .addNetworkInterceptor(cacheInterceptor)//这里大家一定要注意了是addNetworkOnterceptor别搞错了啊。
                .cache(cache)
                .build();

猜你喜欢

转载自blog.csdn.net/weixin_42429629/article/details/81095450