Retrofit实现持久化Cookie的三种方案

本文深入分析了Retrofit中非持久化Cookie的实现原理,并介绍了三种实现Cookie持久化的方案:自定义InDiskCookieStore、自定义拦截器和自定义CookieJar。通过理解CookieJar接口和CookieManager,探讨了如何利用Java序列化实现Cookie持久化存储。
摘要由CSDN通过智能技术生成

在上一文中,我们提到retrofit 2.0中如何实现非持久化cookie的两种方案,但并未做过深的解释。
现在我们重点关注JavaNetCookieJar实现非持久化cookie背后的原理。

话不多说,步入正题。


非持久化Cookie实现分析

首先来看上文中提到的非持久化cookie的实现:

 public void setCookies(OkHttpClient.Builder builder) {
        CookieManager cookieManager = new CookieManager();
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
        builder.cookieJar(new JavaNetCookieJar(cookieManager));
    }

现在我们就以这段代码为起点来研究为什么这几行代码就实现了非持久化cookie呢?不难先发现此处实现cookie的关键就是cookieJar(),我们就以该方法切入。
首先来看该方法的源码:

     //设置cookie处理器,如果没设置,则使用CookieJar.NO_COOKIES作为默认的处理器
    public Builder cookieJar(CookieJar cookieJar) {
      if (cookieJar == null) throw new NullPointerException("cookieJar == null");
      this.cookieJar = cookieJar;
      return this;
    }

通过该方法我们知道这里的关键就在于CookieJar接口,来看看这个接口的定义:

public interface CookieJar {
   
 //默认的cookie处理器,不接受任何cookie
  CookieJar NO_COOKIES = new CookieJar() {
    @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
    }

    @Override public List<Cookie> loadForRequest(HttpUrl url) {
      return Collections.emptyList();
    }
  };


   //根绝cookie处理策略,保存响应中的cookie
  void saveFromResponse(HttpUrl url, List<Cookie> cookies);

  //为请求添加cookie 
  List<Cookie> loadForRequest(HttpUrl url);
}

该接口非常简单,提供了保存和加载cookie的两个方法loadForRequest(HttpUrl url)saveFromResponse(HttpUrl url,List<Cookie> cookies),这就意味这我们可以自行实现接口来实现对cookie管理。到这里想必各位可能已经在想“我们自行实现该接口来将cookie保存到本地,使用的时候再从本地读取,这样不久实现cookie持久化了么?”,这当然没问题,但我们先继续往下看。

除此之外,该接口中存在一个默认的实现NO_COOKIES。

接下来,我们来看看该接口的另外一个实现类JavaNetCookieJar,它本质上只是java.net.CookieHandler的代理类。同样,来看一下JavaNetCookieJar中的源码:

public final class JavaNetCookieJar implements CookieJar {
   
  private final CookieHandler cookieHandler;

  public JavaNetCookieJar(CookieHandler cookieHandler) {
    this.cookieHandler = cookieHandler;
  }


  @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
    if (cookieHandler != null) {
      List<String> cookieStrings = new ArrayList<>();
      for (Cookie cookie : cookies) {
  //遍历cookie集合
        cookieStrings.add(cookie.toString());
      }
      Map<String, List<String>> multimap = Collections.singletonMap("Set-Cookie", cookieStrings);
      try {
      //具体的保存工作交给cookieHandler去处理
        cookieHandler.put(url.uri(), multimap);
      } catch (IOException e) {
        Internal.logger.log(WARNING, "Saving cookies failed for " + url.resolve("/..."), e);
      }
    }
  }

  @Override public List<Cookie> loadForRequest(HttpUrl url) {
    // The RI passes all headers. We don't have 'em, so we don't pass 'em!
    Map<String, List<String>> headers = Collections.emptyMap();
    Map<String, List<String>> cookieHeaders;
    try {
      //从cookieHandler中取出cookie集合。
      cookieHeaders = cookieHandler.get(url.uri(), headers);
    } catch (IOException e) {
      Internal.logger.log(WARNING, "Loading cookies failed for " + url.resolve("/..."), e);
      return Collections.emptyList();
    }

    List<Cookie> cookies = null;
    for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) {
      String key = entry.getKey();
      if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key))
          && !entry.getValue().isEmpty()) {
        for (String header : entry.getValue()) {
          if (cookies == null) cookies = new ArrayList<>();
          cookies.addAll(decodeHeaderAsJavaNetCookies(url, header));
        }
      }
    }

    return cookies != null
        ? Collections.unmodifiableList(cookies)
        : Collections.<Cookie>emptyList();
  }


   //将请求Header转为OkHttp中HttpCookie
  private List<Cookie> decodeHeaderAsJavaNetCookies(HttpUrl url, String header) {
    List<Cookie> result = new ArrayList<>();
    for (int pos = 0, limit = header.length(), pairEnd; pos < limit; pos = pairEnd + 1) {
      //具体转换过程在此不做展示
    }
    return result;
  }
}

上面的代码非常简单,其核心无非在于通过CookieHandler实现对cookie的保存和取值。既然,真正的工作类是CookieHandler,那我们就重点关注CookieHandler.

public abstract class CookieHandler {
   

    private static CookieHandler cookieHandler;

    public synchronized static CookieHandler getDefault() {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SecurityConstants.GET_COOKIEHANDLER_PERMISSION);
        }
        return cookieHandler;
    }

    public synchronized static void setDefault(CookieHandler cHandler) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SecurityConstants.SET_COOKIEHANDLER_PERMISSION);
        }
        cookieHandler = cHandler;
    }

    public abstract Map<String, List<String>>
        get(URI uri, Map<String, List<String>> requestHeaders)
        throws IOException;

    public
  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值