博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
okHttp--Retrofit网络缓存设置总结
阅读量:6645 次
发布时间:2019-06-25

本文共 10197 字,大约阅读时间需要 33 分钟。

前言

找了些文章,发现说的都不是很清楚.设置始终有点问题
这个配置,每个人的需求不一样,实现情况肯定也不一样.
说说我的需求:
1.有网的时候所有接口不使用缓存2.指定的接口产生缓存文件,其他接口不会产生缓存文件3.无网的时候指定的接口使用缓存数据.其他接口不使用缓存数据复制代码

1.网络拦截器(关键)

提示:只能缓存Get请求

Interceptor cacheInterceptor = new Interceptor() {            @Override            public Response intercept(Chain chain) throws IOException {                //拿到请求体                Request request = chain.request();                //读接口上的@Headers里的注解配置                String cacheControl = request.cacheControl().toString();                //判断没有网络并且添加了@Headers注解,才使用网络缓存.                if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){                    //重置请求体;                    request = request.newBuilder()                              //强制使用缓存                            .cacheControl(CacheControl.FORCE_CACHE)                            .build();                }             //如果没有添加注解,则不缓存                if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) {                    //响应头设置成无缓存                    cacheControl = "no-store";                } else if (Utils.isOpenInternet()) {                    //如果有网络,则将缓存的过期时间,设置为0,获取最新数据                    cacheControl = "public, max-age=" + 0;                }else {                    //...如果无网络,则根据@headers注解的设置进行缓存.                }                Response response = chain.proceed(request);                HLog.i("httpInterceptor", cacheControl);                return response.newBuilder()                        .header("Cache-Control", cacheControl)                        .removeHeader("Pragma")                        .build();        };复制代码

具体接口中的使用,添加headers:

/**   * 只能缓存get请求.   * 这里我设置了1天的缓存时间   * 接口随便写的.哈哈,除了 @Headers(...),其它代码没啥参考价值.   */    @Headers("Cache-Control: public, max-age=" + 24 * 3600)    @GET("url")    Observable
queryInfo(@Query("userName") String userName);复制代码

关于Cache-Control头的参数说明:

public	所有内容都将被缓存(客户端和代理服务器都可缓存)private	内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)no-cache	no-cache是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。 no-store	所有内容都不会被缓存到缓存或 Internet 临时文件中max-age=xxx (xxx is numeric)	缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高max-stale和max-age一样,只能设置在请求头里面。同时设置max-stale和max-age,缓存失效的时间按最长的算。(这个其实不用纠结)复制代码

还有2个参数:

CacheControl.FORCE_CACHE 强制使用缓存,如果没有缓存数据,则抛出504(only-if-cached) CacheControl.FORCE_NETWORK 强制使用网络,不使用任何缓存.

这两个设置,不会判断是否有网.需要自己写判断. 设置错误会导致,数据不刷新,或者有网情况下,请求不到数据 这两个很关键..可以根据自己的需求,进行切换.

2.设置OkHttpClient

OkHttpClient client = new OkHttpClient.Builder()                //添加log拦截器,打印log信息,代码后面贴出                .addInterceptor(loggingInterceptor)                //添加上面代码的拦截器,设置缓存                .addNetworkInterceptor(cacheInterceptor)                //这个也要添加,否则无网的时候,缓存设置不会生效                .addInterceptor(cacheInterceptor)                //设置缓存目录,以及最大缓存的大小,这里是设置10M                .cache(new Cache(MyApplication.getContext().getCacheDir(), 10240 * 1024))                .build();复制代码

3.完整的代码:

public class RetrofitUtil {    /**     * 服务器地址     */    private static final String API_HOST = Constant.URLS.BASEURL;  private RetrofitUtil() {    }    public static Retrofit getRetrofit() {        return Instanace.retrofit;    }    private static Retrofit getInstanace() {        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {            @Override            public void log(String message) {                HLog.i("RxJava", message);            }        });        Interceptor cacheInterceptor = new Interceptor() {            @Override            public Response intercept(Chain chain) throws IOException {                Request request = chain.request();                //有网的时候,读接口上的@Headers里的注解配置                String cacheControl = request.cacheControl().toString();                //没有网络并且添加了注解,才使用缓存.                if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){                    //重置请求体;                    request = request.newBuilder()                            .cacheControl(CacheControl.FORCE_CACHE)                            .build();                }             //如果没有添加注解,则不缓存                if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) {                    //响应头设置成无缓存                    cacheControl = "no-store";                } else if (Utils.isOpenInternet()) {                    //如果有网络,则将缓存的过期事件,设置为0,获取最新数据                    cacheControl = "public, max-age=" + 0;                }else {                    //...如果无网络,则根据@headers注解的设置进行缓存.                }                Response response = chain.proceed(request);                HLog.i("httpInterceptor", cacheControl);                return response.newBuilder()                        .header("Cache-Control", cacheControl)                        .removeHeader("Pragma")                        .build();            }        };        OkHttpClient client = new OkHttpClient.Builder()                .addInterceptor(loggingInterceptor)                .addNetworkInterceptor(cacheInterceptor)                .addInterceptor(cacheInterceptor)                .cache(new Cache(MyApplication.getContext().getCacheDir(), 10240 * 1024))                .build();        return new Retrofit.Builder()                .client(client)                .baseUrl(API_HOST)                .addConverterFactory(FastjsonConverterFactory.create())                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .build();    }    private static class Instanace {        private static final Retrofit retrofit = getInstanace();    } }复制代码

附上HttpLoggingInterceptor

/** * Created by Sunflower on 2016/1/12. */public class HttpLoggingInterceptor implements Interceptor {    private static final Charset UTF8 = Charset.forName("UTF-8");    public enum Level {        /**         * No logs.         */        NONE,        /**         * Logs request and response lines.         * 

* Example: *
{@code         * --> POST /greeting HTTP/1.1 (3-byte body)         * 

* <-- HTTP/1.1 200 OK (22ms, 6-byte body) * }
*/ BASIC, /** * Logs request and response lines and their respective headers. *

* Example: *
{@code         * --> POST /greeting HTTP/1.1         * Host: example.com         * Content-Type: plain/text         * Content-Length: 3         * --> END POST         * 

* <-- HTTP/1.1 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 * <-- END HTTP * }
*/ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). *

* Example: *
{@code         * --> POST /greeting HTTP/1.1         * Host: example.com         * Content-Type: plain/text         * Content-Length: 3         * 

* Hi? * --> END GET *

* <-- HTTP/1.1 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 *

* Hello! * <-- END HTTP * }
*/ BODY } public interface Logger { void log(String message); /** * A {@link Logger} defaults output appropriate for the current platform. */ Logger DEFAULT = new Logger() { @Override public void log(String message) { Platform.get().log(Platform.WARN,message,null); } }; } public HttpLoggingInterceptor() { this(Logger.DEFAULT); } public HttpLoggingInterceptor(Logger logger) { this.logger = logger; } private final Logger logger; private volatile Level level = Level.BODY; /** * Change the level at which this interceptor logs. */ public HttpLoggingInterceptor setLevel(Level level) { if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); this.level = level; return this; } @Override public Response intercept(Chain chain) throws IOException { Level level = this.level; Request request = chain.request(); if (level == Level.NONE) { return chain.proceed(request); } boolean logBody = level == Level.BODY; boolean logHeaders = logBody || level == Level.HEADERS; RequestBody requestBody = request.body(); boolean hasRequestBody = requestBody != null; String requestStartMessage = request.method() + ' ' + request.url(); if (!logHeaders && hasRequestBody) { requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; } logger.log(requestStartMessage); if (logHeaders) { if (!logBody || !hasRequestBody) { logger.log("--> END " + request.method()); } else if (bodyEncoded(request.headers())) { logger.log("--> END " + request.method() + " (encoded body omitted)"); } else if (request.body() instanceof MultipartBody) { //如果是MultipartBody,会log出一大推乱码的东东 } else { Buffer buffer = new Buffer(); requestBody.writeTo(buffer); Charset charset = UTF8; MediaType contentType = requestBody.contentType(); if (contentType != null) { contentType.charset(UTF8); } logger.log(buffer.readString(charset));// logger.log(request.method() + " (" + requestBody.contentLength() + "-byte body)"); } } long startNs = System.nanoTime(); Response response = chain.proceed(request); long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); logger.log(response.code() + ' ' + response.message() + " (" + tookMs + "ms" + ')'); return response; } private boolean bodyEncoded(Headers headers) { String contentEncoding = headers.get("Content-Encoding"); return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); } private static String protocol(Protocol protocol) { return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1"; }}复制代码

您的喜欢与回复是我最大的动力-_-

转载地址:http://cvrvo.baihongyu.com/

你可能感兴趣的文章
深入理解Vue.js轻量高效的前端组件化方案
查看>>
ApacheCN 翻译活动进度公告 2019.2.18
查看>>
Vultr 教程目录
查看>>
mysql 的delete from where 子查询的一些限制
查看>>
POS概述
查看>>
社区投稿 | DBLE rule.xml 配置解析
查看>>
mysqll索引实验
查看>>
面试题·HashMap和Hashtable的区别(转载再整理)
查看>>
算法入门
查看>>
【React深入】setState的执行机制
查看>>
微信域名防封接口的应用场景
查看>>
116. Populating Next Right Pointers in Each Node
查看>>
使用Envoy 作Sidecar Proxy的微服务模式-2.超时和重试
查看>>
每日两道前端面试题20190220
查看>>
自底向上的web数据操作指南
查看>>
在使用spring-boot-maven-plugin的下生成普通的jar包
查看>>
Vue-SuperSlide(SuperSlide component for Vue)
查看>>
应用监控的选型思考
查看>>
MaxCompute表设计最佳实践
查看>>
https简单解读
查看>>