美文网首页
网络访问组件六- 让 okhttp 支持 post缓存

网络访问组件六- 让 okhttp 支持 post缓存

作者: zhaoyubetter | 来源:发表于2017-04-27 20:54 被阅读244次

    参考:

    1. http://www.jianshu.com/p/2710ed1e6b48

    整体代码与示例,请参考:

    https://github.com/zhaoyubetter/basenet
    至此网络模块的封装告一段落;

    为什么需要POST缓存

    大环境所致,在servlet中,有2个方法,分别是 doGet, doPost,要么在 doGet中,转发到了doPost,要么反之,springMVC,已记不清了。
    所以这就造成了,有时候,我们真的需要 为 post添加缓存;

    为post请求添加缓存原理

    参考图片:
    在 application 级别拦截请求,因为:应用拦截器允许短路而不调用 Chain.proceed(),即中止调用
    判断如果是 post,如果缓存有效,直接返回response,让后续的拦截器无法执行;
    其他缓存的内容,几乎都是 Cache.java那套;少量修改;


    图片来自网络

    具体实现:

    1. 为 OkhttpClient添加应用拦截器:

       final OkHttpClient.Builder builder = new OkHttpClient.Builder();
       builder.connectTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS);
       builder.readTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS);
       builder.writeTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS);
      
       /* ==设置拦截器== */
       // 设置缓存
       File cacheDir = new File(NetConfig.getInstance().getCacheDir());
       // GET 形式缓存设置
       Cache cache = new Cache(cacheDir, NetConfig.getInstance().getCacheSize());
       builder.cache(cache).addNetworkInterceptor(new NetCacheInterceptor());        // 设置缓存拦截器
       // 日志拦截
       if (NetConfig.getInstance().isDebug()) {
           builder.addInterceptor(new LoggerInterceptor());
       }
       // 是否允许POST 形式缓存设置
       if (NetConfig.getInstance().isEnablePostCache()) {
           builder.addInterceptor(new PostCacheInterceptor());
       }
      
    2. 新增类 NetPostCache.java, 此类,就是 copy 了 Cache类,然后修改
      其put方法,让其支持post,与 获取key方法,如下:

    public static String key(Request request) {
            String cUrl = request.url().toString();
            if (request.body() != null) {
                Buffer buffer = new Buffer();
                try {
                    // 避免post重复,这里采用value来凭借,因key不好获取
                    // 如果有上传下载文件,此处为 ProgressRequestBody
                    if (request.body() instanceof MultipartBody) {
                        final List<MultipartBody.Part> parts = ((MultipartBody) request.body()).parts();
                        /**
                         * 接受字符串格式的参数,其他忽略
                         * @see lib.basenet.okhttp.OkHttpRequest#getRequestBody mParams
                         */
                        for (MultipartBody.Part p : parts) {
                            if (null == p.body().contentType()) {
                                p.body().writeTo(buffer);
                            }
                        }
                    }
                    String params = buffer.readString(Charset.forName("UTF-8")); //获取请求参数
                    cUrl += params;
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    Util.closeQuietly(buffer);
                }
    
            }
            return ByteString.encodeUtf8(cUrl).md5().hex();
        }
    
    1. 应用级拦截器:PostCacheInterceptor.java 代码片段
    /**
     * post缓存,从应用拦截器层,拦截
     * Created by zhaoyu on 2017/4/26.
     */
    public class PostCacheInterceptor implements Interceptor {
    
        /**
         * 缓存Post请求
         */
        final NetPostCache mPostCache;
    
        public PostCacheInterceptor() {
            File cacheDir = new File(NetConfig.getInstance().getCacheDir() + "/post");
            mPostCache = new NetPostCache(cacheDir, NetConfig.getInstance().getCacheSize());
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            final Request request = chain.request();
    
            // 如果是post请求,并且设置了缓存,则在这里进行拦截,如果缓存有效,后续的拦截器将不执行
            if ("POST".equalsIgnoreCase(request.method()) && (null != request.cacheControl() && !request.cacheControl().noStore())) {
                // 强制刷新,删除旧有post缓存
                checkForceRefresh(request);
    
                // 以下代码逻辑来家:okhttp3 源码中的 CacheInterceptor.java,模拟其运行
                Response cacheCandidate = mPostCache != null ? mPostCache.get(request) : null;
                long now = System.currentTimeMillis();
                CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
                Request networkRequest = strategy.networkRequest;
                Response cacheResponse = strategy.cacheResponse;
    
                if (mPostCache != null) {
                    mPostCache.trackResponse(strategy);
                }
    
                if (cacheCandidate != null && cacheResponse == null) {
                    closeQuietly(cacheCandidate.body()); // The mPostCache candidate wasn't applicable. Close it.
                }
    
                // 有则从缓存中返回,直接跳过后面的拦截器,不访问网络了
                // If we don't need the network, we're done.
                if (networkRequest == null) {
                    return cacheResponse.newBuilder()
                            .cacheResponse(stripBody(cacheResponse))
                            .build();
                }
    
                Response networkResponse = null;
                try {
                    // 执行网络请求,并包装一下
                    networkResponse = chain.proceed(request);
                } finally {
                    // If we're crashing on I/O or otherwise, don't leak the mPostCache body.
                    if (networkResponse == null && cacheCandidate != null) {
                        closeQuietly(cacheCandidate.body());
                    }
                }
    
                if (HttpHeaders.hasBody(networkResponse)) {
                    CacheRequest cacheRequest = mPostCache.put(networkResponse);
                    networkResponse = cacheWritingResponse(cacheRequest, networkResponse);
                }
    
                // 当 onSuccess调用时,会写入缓存
                return networkResponse;
            }
    
            return chain.proceed(request);
        }
    

    注意事项:

    post 缓存时,因 唯一key,不好定位,只支持 请求参数为 键值对(key-value)form 表单形式,对于上传文件,下载文件形式的post,请求,一律无效;

    相关文章

      网友评论

          本文标题:网络访问组件六- 让 okhttp 支持 post缓存

          本文链接:https://www.haomeiwen.com/subject/fxmnzttx.html