Okhttp笔记

addInterceptor与addNetworkInterceptor

addInterceptor

    /**
     * Returns a modifiable list of interceptors that observe the full span of each call: from
     * before the connection is established (if any) until after the response source is selected
     * (either the origin server, cache, or both).
     */
    public List<Interceptor> interceptors() {
      return interceptors;
    }

    public Builder addInterceptor(Interceptor interceptor) {
      interceptors.add(interceptor);
      return this;
    }

Application interceptors

  1. Don’t need to worry about intermediate responses like redirects and retries.
  2. Are always invoked once, even if the HTTP response is served from the cache.
  3. Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match.
  4. Permitted to short-circuit and not call Chain.proceed().
  5. Permitted to retry and make multiple calls to Chain.proceed().
  1. 不需要担心中间过程的响应,如重定向和重试.
  2. 总是只调用一次,即使HTTP响应是从缓存中获取.
  3. 观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
  4. 允许短路(从缓存中获取,不进行网络请求)而不调用 Chain.proceed(),即中止调用.
  5. 允许重试,使 Chain.proceed()调用多次.

addNetworkInterceptor

    /**
     * Returns a modifiable list of interceptors that observe a single network request and response.
     * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error
     * for a network interceptor to short-circuit or repeat a network request.
     */
    public List<Interceptor> networkInterceptors() {
      return networkInterceptors;
    }

    public Builder addNetworkInterceptor(Interceptor interceptor) {
      networkInterceptors.add(interceptor);
      return this;
    }

Network Interceptors

  1. Able to operate on intermediate responses like redirects and retries.
  2. Not invoked for cached responses that short-circuit the network.
  3. Observe the data just as it will be transmitted over the network.
  4. Access to the Connection that carries the request.
  1. 能够操作中间过程的响应,如重定向和重试.
  2. 当网络短路而返回缓存响应时不被调用.
  3. 只观察在网络上传输的数据.
  4. 携带请求来访问连接.

Cache

okhttp只会对get请求进行缓存,post请求是不会进行缓存,这也是有道理的,因为get请求的数据一般是比较持久的,而post一般是交互操作,没太大意义进行缓存。

Retrofit2.0+Okhttp3 缓存封装

  1. 配置权限
<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
  1. 配置okhttp3 cache
    @Provides
    @Singleton
    @HaveCache
    OkHttpClient provide CacheOkHttpClient(OkHttpClient.Builder builder) {
        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
            builder.addInterceptor(loggingInterceptor);
        }

        File cacheFile = new File(Constants.PATH_HTTP_CACHE);
        if(!cacheFile.exists()){
            cacheFile.mkdirs();
        }
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
        builder.addNetworkInterceptor(cacheInterceptor);
        builder.addInterceptor(interceptor);
        builder.cache(cache);
        builder.connectTimeout(10, TimeUnit.SECONDS);
        builder.readTimeout(20, TimeUnit.SECONDS);
        builder.writeTimeout(20, TimeUnit.SECONDS);
        builder.retryOnConnectionFailure(true);
        return builder.build();
    }
  1. 自定义请求策略
public class CacheTag {
    public static final String NO_CACHE = "NO_CACHE";//不缓存服务器数据
    public static final String ONLY_CACHE = "ONLY_CACHE";//只使用缓存
    public static final String ONLY_NETWORK = "ONLY_NETWORK";//只使用网络
    public static final String CACHE_ELSE_NETWORK = "CACHE_ELSE_NETWORK";//先查询本地缓存,没有则从网络获取
    public static final String NETWORK_ELSE_CACHE = "NETWORK_ELSE_CACHE";//先通过网络获取,没有则使用本地缓存
}
  1. Retrofit 进行get请求

    • 固定缓存策略

       @Headers("cacheTag:缓存策略")
       @GET("method/test")
       Flowable<ResultMessage> getXXX(@Query("param1") String param1);
    • 可配置缓存策略

    @GET("method/test")
    Flowable<ResultMessage> getXXX(@Header("cacheTag") String cache,@Query("param1") String param1);
  2. 通过拦截器实现缓存策略

    private void buildCache(OkHttpClient.Builder builder) {
        File cacheFile = new File(Constants.PATH_HTTP_CACHE);
        final Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
        builder.cache(cache);
        Interceptor networkInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = chain.proceed(request);
                int maxAge = 60 * 60 * 24 * 28;
                response.newBuilder().header("Cache-Control", "public,max-age=" + maxAge)
                        .removeHeader("Pragma")
                        .build();//默认全部缓存,过期时间为4周。
                List<String> cacheTag = request.headers("cacheTag");
                if (!ListUtil.isEmpty(cacheTag)) {
                    for (String tag : cacheTag) {
                        if (CacheTag.NO_CACHE.equalsIgnoreCase(tag)) {
                            response.newBuilder().header("Cache-Control", "no-store")
                                    .removeHeader("Pragma")
                                    .build();//修改响应头,不缓存。
                        }
                    }
                }
                return response;
            }
        };

        Interceptor interceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = null;
                List<String> cacheTag = request.headers("cacheTag");
                if (!ListUtil.isEmpty(cacheTag)) {
                    for (String tag : cacheTag) {
                        if (CacheTag.ONLY_CACHE.equalsIgnoreCase(tag)) {//只从缓存中读
                            request = request.newBuilder()
                                    .cacheControl(CacheControl.FORCE_CACHE)
                                    .build();
                        } else if (CacheTag.ONLY_NETWORK.equalsIgnoreCase(tag)) {//只从网络中获取
                            if (SystemUtil.isNetworkConnected()) {
                                request = request.newBuilder()
                                        .cacheControl(CacheControl.FORCE_NETWORK)
                                        .build();
                            }else {//若网络不可用直接抛出异常
                                throw new IOException("网络不可用!");
                            }
                        } else if (CacheTag.CACHE_ELSE_NETWORK.equalsIgnoreCase(tag)) {//先从缓存中获取,若无再请求网络
                            request = request.newBuilder()
                                    .cacheControl(CacheControl.FORCE_CACHE)
                                    .build();
                            response = chain.proceed(request);
                            Response cacheResponse = response.cacheResponse();
                            if (cacheResponse == null) {//无缓存的情况,从网络获取
                                response = null;
                                request = request.newBuilder()
                                        .cacheControl(CacheControl.FORCE_NETWORK)
                                        .build();
                            }
                        } else if (CacheTag.NETWORK_ELSE_CACHE.equalsIgnoreCase(tag)) {//先进行网络请求,请求失败再获取缓存
                            if (SystemUtil.isNetworkConnected()) {
                                request = request.newBuilder()
                                        .cacheControl(CacheControl.FORCE_NETWORK)
                                        .build();
                                try {
                                    response = chain.proceed(request);
                                } catch (Exception e) {//抛出异常,表示网络请求失败,改从本地获取
                                    request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE)
                                            .build();
                                }
                            } else {//网络不可用,直接从本地获取
                                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE)
                                        .build();
                            }
                        } else if (CacheTag.CACHE_AND_NETWORK.equalsIgnoreCase(tag)) {
                            request = request.newBuilder()
                                    .cacheControl(CacheControl.FORCE_CACHE)
                                    .build();
                            Response proceed = chain.proceed(request);

                        }
                    }
                }

                if (response == null) {
                    response = chain.proceed(request);
                }
                return response;
            }
        };
        builder.addNetworkInterceptor(networkInterceptor);
        builder.addInterceptor(interceptor);
    }

no-cache 和 no-store

  /**
   * In a response, this field's name "no-cache" is misleading. It doesn't prevent us from caching
   * the response; it only means we have to validate the response with the origin server before
   * returning it. We can do this with a conditional GET.
   *
   * <p>In a request, it means do not use a cache to satisfy the request.
   */
  public boolean noCache() {
    return noCache;
  }

  /** If true, this response should not be cached. */
  public boolean noStore() {
    return noStore;
  }

Cache-Control 常见值

  • max-age:这个参数告诉浏览器将页面缓存多长时间,超过这个时间后才再次向服务器发起请求检查页面是否有更新。对于静态的页面,比如图片、CSS、Javascript,一般都不大变更,因此通常我们将存储这些内容的时间设置为较长的时间,这样浏览器会不会向浏览器反复发起请求,也不会去检查是否更新了。
  • s-maxage:这个参数告诉缓存服务器(proxy,如Squid)的缓存页面的时间。如果不单独指定,缓存服务器将使用max-age。对于动态内容(比如文档的查看页面),我们可告诉浏览器很快就过时了(max-age=0),并告诉缓存服务器(Squid)保留内容一段时间(比如,s-maxage=7200)。一旦我们更新文档,我们将告诉Squid清除老的缓存版本。
  • must-revalidate:这告诉浏览器,一旦缓存的内容过期,一定要向服务器询问是否有新版本。
  • proxy-revalidate:proxy上的缓存一旦过期,一定要向服务器询问是否有新版本。
  • no-cache:不做缓存。
  • no-store:数据不在硬盘中临时保存,这对需要保密的内容比较重要。
  • public:告诉缓存服务器, 即便是对于不该缓存的内容也缓存起来,比如当用户已经认证的时候。所有的静态内容(图片、Javascript、CSS等)应该是public的。
  • private:告诉proxy不要缓存,但是浏览器可使用private cache进行缓存。一般登录后的个性化页面是private的。
  • no-transform: 告诉proxy不进行转换,比如告诉手机浏览器不要下载某些图片。
  • max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值