乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      OkHttp3之Cookies管理及持久化

       小飛苑 2017-02-24

      okHttp3正式版剛發(fā)布了沒幾天,正好重構之前的代碼,于是第一時間入坑了。對okHttp3的一些改變,會陸續(xù)寫下來,這是第一篇cookies管理及持久化。

      Cookies管理

      OkHttp的源碼過于復雜,感興趣的同學可以自行閱讀,這里只針對HttpEngineer類進行分析,從字面意思即可看出這個類負責http請求的request、response等等操作的處理,而cookies管理也是隨著http請求的request、response來處理。

      3.0之前

      先看NetworkRequest方法,在里面通過client.getCookieHandler()函數(shù)獲得了CookieHandler對象,通過該對象拿到cookie并設置到請求頭里,請求結束后取得響應后通過networkResponse.headers()函數(shù)將請求頭獲得傳入receiveHeaders函數(shù),并將取得的cookie存入getCookieHandler得到的一個CookieHandler對象中去

      private Request networkRequest(Request request) throws IOException {
        Request.Builder result = request.newBuilder();
      
        //例行省略....
      
        CookieHandler cookieHandler = client.getCookieHandler();
        if (cookieHandler != null) {
          // Capture the request headers added so far so that they can be offered to the CookieHandler.
          // This is mostly to stay close to the RI; it is unlikely any of the headers above would
          // affect cookie choice besides "Host".
          Map<String, List<String>> headers = OkHeaders.toMultimap(result.build().headers(), null);
      
          Map<String, List<String>> cookies = cookieHandler.get(request.uri(), headers);
      
          // Add any new cookies to the request.
          OkHeaders.addCookies(result, cookies);
        }
      
        //例行省略....
      
        return result.build();
      }
      public void readResponse() throws IOException {
        //例行省略....
      
        receiveHeaders(networkResponse.headers());
      
        //例行省略....
      }
      public void receiveHeaders(Headers headers) throws IOException {
        CookieHandler cookieHandler = client.getCookieHandler();
        if (cookieHandler != null) {
          cookieHandler.put(userRequest.uri(), OkHeaders.toMultimap(headers, null));
        }
      }

      CookieHandler對象是OkHttpClient類中的一個屬性,傳入了這個對象,那么OkHttp就會對cookie進行自動管理

      private CookieHandler cookieHandler;
      public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
        this.cookieHandler = cookieHandler;
        return this;
      }
      
      public CookieHandler getCookieHandler() {
        return cookieHandler;
      }
      OkHttpClient client = new OkHttpClient();
      client.setCookieHandler(CookieHandler cookieHanlder);

      3.0之后

      而在OkHttp3中,對cookie而言,新增了兩個類Cookiejar、Cookie兩個類,在了解這兩個類之前,先去看一下HttpEngine關于cookie管理的變化

      private Request networkRequest(Request request) throws IOException {
          Request.Builder result = request.newBuilder();
      
          //例行省略....
          
          List<Cookie> cookies = client.cookieJar().loadForRequest(request.url());
          if (!cookies.isEmpty()) {
            result.header("Cookie", cookieHeader(cookies));
          }
      
          //例行省略....
      
          return result.build();
        }
      private String cookieHeader(List<Cookie> cookies) {
          StringBuilder cookieHeader = new StringBuilder();
          for (int i = 0, size = cookies.size(); i < size; i++) {
            if (i > 0) {
              cookieHeader.append("; ");
            }
            Cookie cookie = cookies.get(i);
            cookieHeader.append(cookie.name()).append('=').append(cookie.value());
          }
          return cookieHeader.toString();
        }
      public void receiveHeaders(Headers headers) throws IOException {
          if (client.cookieJar() == CookieJar.NO_COOKIES) return;
      
          List<Cookie> cookies = Cookie.parseAll(userRequest.url(), headers);
          if (cookies.isEmpty()) return;
      
          client.cookieJar().saveFromResponse(userRequest.url(), cookies);
        }

      通過以上幾個關鍵方法,可以很明顯的感覺到作者的意圖了,為了更加自由定制化的cookie管理。其中loadForRequest()saveFromResponse()這兩個方法最為關鍵,分別是在發(fā)送時向request header中加入cookie,在接收時,讀取response header中的cookie?,F(xiàn)在再去看Cookiejar這個類,就很好理解了

      public interface CookieJar {
        /** A cookie jar that never accepts any cookies. */
        CookieJar NO_COOKIES = new CookieJar() {
          @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
          }
      
          @Override public List<Cookie> loadForRequest(HttpUrl url) {
            return Collections.emptyList();
          }
        };
      
        /**
         * Saves {@code cookies} from an HTTP response to this store according to this jar's policy.
         *
         * <p>Note that this method may be called a second time for a single HTTP response if the response
         * includes a trailer. For this obscure HTTP feature, {@code cookies} contains only the trailer's
         * cookies.
         */
        void saveFromResponse(HttpUrl url, List<Cookie> cookies);
      
        /**
         * Load cookies from the jar for an HTTP request to {@code url}. This method returns a possibly
         * empty list of cookies for the network request.
         *
         * <p>Simple implementations will return the accepted cookies that have not yet expired and that
         * {@linkplain Cookie#matches match} {@code url}.
         */
        List<Cookie> loadForRequest(HttpUrl url);
      }

      so!在OkHttpClient創(chuàng)建時,傳入這個CookieJar的實現(xiàn),就能完成對Cookie的自動管理了

      OkHttpClient client = new OkHttpClient.Builder()
          .cookieJar(new CookieJar() {
              private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
      
              @Override
              public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                  cookieStore.put(url, cookies);
              }
      
              @Override
              public List<Cookie> loadForRequest(HttpUrl url) {
                  List<Cookie> cookies = cookieStore.get(url);
                  return cookies != null ? cookies : new ArrayList<Cookie>();
              }
          })
          .build();

      Cookies持久化

      對Cookies持久化的方案,與之前版本并無很大區(qū)別,還是參考android-async-http這個庫,主要參考其中兩個類:

      • PersistentCookieStore

      • SerializableHttpCookie
        與之前版本的區(qū)別是要將對Java.net.HttpCookie這個類的緩存處理換成對okhttp3.Cookie的處理,其他方面幾乎一樣。

      廢話不多說了,直接上代碼

      SerializableOkHttpCookies

      主要做兩件事:

      • 將Cookie對象輸出為ObjectStream

      • 將ObjectStream序列化成Cookie對象

      public class SerializableOkHttpCookies implements Serializable {
      
          private transient final Cookie cookies;
          private transient Cookie clientCookies;
      
          public SerializableOkHttpCookies(Cookie cookies) {
              this.cookies = cookies;
          }
      
          public Cookie getCookies() {
              Cookie bestCookies = cookies;
              if (clientCookies != null) {
                  bestCookies = clientCookies;
              }
              return bestCookies;
          }
      
          private void writeObject(ObjectOutputStream out) throws IOException {
              out.writeObject(cookies.name());
              out.writeObject(cookies.value());
              out.writeLong(cookies.expiresAt());
              out.writeObject(cookies.domain());
              out.writeObject(cookies.path());
              out.writeBoolean(cookies.secure());
              out.writeBoolean(cookies.httpOnly());
              out.writeBoolean(cookies.hostOnly());
              out.writeBoolean(cookies.persistent());
          }
      
          private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
              String name = (String) in.readObject();
              String value = http://segmentfault.com/a/(String) in.readObject();
              long expiresAt = in.readLong();
              String domain = (String) in.readObject();
              String path = (String) in.readObject();
              boolean secure = in.readBoolean();
              boolean httpOnly = in.readBoolean();
              boolean hostOnly = in.readBoolean();
              boolean persistent = in.readBoolean();
              Cookie.Builder builder = new Cookie.Builder();
              builder = builder.name(name);
              builder = builder.value(value);
              builder = builder.expiresAt(expiresAt);
              builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);
              builder = builder.path(path);
              builder = secure ? builder.secure() : builder;
              builder = httpOnly ? builder.httpOnly() : builder;
              clientCookies =builder.build();
          }
      }

      PersistentCookieStore

      根據(jù)一定的規(guī)則去緩存或者獲取Cookie:

      public class PersistentCookieStore {
          private static final String LOG_TAG = "PersistentCookieStore";
          private static final String COOKIE_PREFS = "Cookies_Prefs";
      
          private final Map<String, ConcurrentHashMap<String, Cookie>> cookies;
          private final SharedPreferences cookiePrefs;
      
      
          public PersistentCookieStore(Context context) {
              cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
              cookies = new HashMap<>();
      
              //將持久化的cookies緩存到內存中 即map cookies
              Map<String, ?> prefsMap = cookiePrefs.getAll();
              for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
                  String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");
                  for (String name : cookieNames) {
                      String encodedCookie = cookiePrefs.getString(name, null);
                      if (encodedCookie != null) {
                          Cookie decodedCookie = decodeCookie(encodedCookie);
                          if (decodedCookie != null) {
                              if (!cookies.containsKey(entry.getKey())) {
                                  cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>());
                              }
                              cookies.get(entry.getKey()).put(name, decodedCookie);
                          }
                      }
                  }
              }
          }
      
          protected String getCookieToken(Cookie cookie) {
              return cookie.name() + "@" + cookie.domain();
          }
      
          public void add(HttpUrl url, Cookie cookie) {
              String name = getCookieToken(cookie);
      
              //將cookies緩存到內存中 如果緩存過期 就重置此cookie
              if (!cookie.persistent()) {
                  if (!cookies.containsKey(url.host())) {
                      cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>());
                  }
                  cookies.get(url.host()).put(name, cookie);
              } else {
                  if (cookies.containsKey(url.host())) {
                      cookies.get(url.host()).remove(name);
                  }
              }
      
              //講cookies持久化到本地
              SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
              prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
              prefsWriter.putString(name, encodeCookie(new SerializableOkHttpCookies(cookie)));
              prefsWriter.apply();
          }
      
          public List<Cookie> get(HttpUrl url) {
              ArrayList<Cookie> ret = new ArrayList<>();
              if (cookies.containsKey(url.host()))
                  ret.addAll(cookies.get(url.host()).values());
              return ret;
          }
      
          public boolean removeAll() {
              SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
              prefsWriter.clear();
              prefsWriter.apply();
              cookies.clear();
              return true;
          }
      
          public boolean remove(HttpUrl url, Cookie cookie) {
              String name = getCookieToken(cookie);
      
              if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) {
                  cookies.get(url.host()).remove(name);
      
                  SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
                  if (cookiePrefs.contains(name)) {
                      prefsWriter.remove(name);
                  }
                  prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
                  prefsWriter.apply();
      
                  return true;
              } else {
                  return false;
              }
          }
      
          public List<Cookie> getCookies() {
              ArrayList<Cookie> ret = new ArrayList<>();
              for (String key : cookies.keySet())
                  ret.addAll(cookies.get(key).values());
      
              return ret;
          }
      
          /**
           * cookies 序列化成 string
           *
           * @param cookie 要序列化的cookie
           * @return 序列化之后的string
           */
          protected String encodeCookie(SerializableOkHttpCookies cookie) {
              if (cookie == null)
                  return null;
              ByteArrayOutputStream os = new ByteArrayOutputStream();
              try {
                  ObjectOutputStream outputStream = new ObjectOutputStream(os);
                  outputStream.writeObject(cookie);
              } catch (IOException e) {
                  Log.d(LOG_TAG, "IOException in encodeCookie", e);
                  return null;
              }
      
              return byteArrayToHexString(os.toByteArray());
          }
      
          /**
           * 將字符串反序列化成cookies
           *
           * @param cookieString cookies string
           * @return cookie object
           */
          protected Cookie decodeCookie(String cookieString) {
              byte[] bytes = hexStringToByteArray(cookieString);
              ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
              Cookie cookie = null;
              try {
                  ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
                  cookie = ((SerializableOkHttpCookies) objectInputStream.readObject()).getCookies();
              } catch (IOException e) {
                  Log.d(LOG_TAG, "IOException in decodeCookie", e);
              } catch (ClassNotFoundException e) {
                  Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);
              }
      
              return cookie;
          }
      
          /**
           * 二進制數(shù)組轉十六進制字符串
           *
           * @param bytes byte array to be converted
           * @return string containing hex values
           */
          protected String byteArrayToHexString(byte[] bytes) {
              StringBuilder sb = new StringBuilder(bytes.length * 2);
              for (byte element : bytes) {
                  int v = element & 0xff;
                  if (v < 16) {
                      sb.append('0');
                  }
                  sb.append(Integer.toHexString(v));
              }
              return sb.toString().toUpperCase(Locale.US);
          }
      
          /**
           * 十六進制字符串轉二進制數(shù)組
           *
           * @param hexString string of hex-encoded values
           * @return decoded byte array
           */
          protected byte[] hexStringToByteArray(String hexString) {
              int len = hexString.length();
              byte[] data = http://segmentfault.com/a/new byte[len / 2];
              for (int i = 0; i < len; i += 2) {
                  data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
              }
              return data;
          }
      }

      最終效果

      完成對Cookie持久化之后,就可以對Cookiejar進行進一步修改了,最終效果:

      /**
           * 自動管理Cookies
           */
          private class CookiesManager implements CookieJar {
              private final PersistentCookieStore cookieStore = new PersistentCookieStore(getApplicationContext());
      
              @Override
              public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                  if (cookies != null && cookies.size() > 0) {
                      for (Cookie item : cookies) {
                          cookieStore.add(url, item);
                      }
                  }
              }
      
              @Override
              public List<Cookie> loadForRequest(HttpUrl url) {
                  List<Cookie> cookies = cookieStore.get(url);
                  return cookies;
              }
          }

      Tips

      在這樣做之前,嘗試了使用InterceptorNetWorkInterceptor在Http請求request和response時,攔截響應鏈,加入對Cookie的管理。so!接下來可能會詳細介紹下Interceptor這個非??岬膶崿F(xiàn)。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多