鴻洋大神の穴を踏んで、彼のCookieの支持がもたらしたBUGを最適化して修復します

5486 ワード

前言:現在、APP内のネットワークフレームワークでRetrofitを使用するのは一般的な現象であるはずですが、ビジネスのニーズでログイン状態を維持する必要がある場合や、サービス側がクライアントにデータを書く必要がある場合があり、次のリクエストでこれらのデータをサービス側に書き返します.PC側のブラウザメカニズムを完全にシミュレートしたので、ここでは鴻洋大神のRetrofitのCookieへのサポートを使用しました.
げんしょう
正常に使用して、問題がないことを発見して、JESSIONIDも正常に使用することができて、会話は維持することができます.昨日楽屋は私に言って、彼はクライアントに他のCOOKIEを書いて、どうして安卓端は帰ってこなかったのですか?
チェック
取り戻せない以上,二つのところに疑いがある
  • 最初のResponseはローカルに
  • と書いていません.
  • 第2のRequestはサーバに
  • を伝えなかった.
    見てみましょうCookieJar.JAvaのソース:
    
    public interface CookieJar {
      /** A cookie jar that never accepts any cookies. */
      CookieJar NO_COOKIES = new CookieJar() {
        @Override public void saveFromResponse(HttpUrl url, List cookies) {
        }
    
        @Override public List loadForRequest(HttpUrl url) {
          return Collections.emptyList();
        }
      };
    
      /**
       * Saves {@code cookies} from an HTTP response to this store according to this jar's policy.
       *
       * 

    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 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. * *

    Simple implementations will return the accepted cookies that have not yet expired and that * {@linkplain Cookie#matches match} {@code url}. */ List loadForRequest(HttpUrl url); }


    ここでは主に2つの方法を見ます.
  • void saveFromResponse(HttpUrl url, List cookies); Responseから
  • とローカルに書く.
  • List loadForRequest(HttpUrl url);ローカルからRequestリクエストに
  • を加える.
    ローカライズにはPersistentCookieStoreが使用されています.JAvaで実現
    ここではまずsaveFromResponse(HttpUrl url,List cookies)の中で、鴻洋大神がこんな一節を書いたのを見てみましょう.
    override fun saveFromResponse(httpUrl: HttpUrl, cookies: List?)
    {
        if ( cookies != null && cookies.isNotEmpty())
        {
            for (item in cookies)
            {
                cookieStore.add(httpUrl, item)
            }
        }
    }
    

    ここでは簡単な判断と、サービス側から返されたクッキーのリストを1つずつローカルに追加し、コード:cookieStore.add(httpUrl, item)という行のポイントソースポイントを追跡します.
    PersistentCookieStore.java
    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());
            }
            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();
        if (url.host() != null && cookies.get(url.host()) != null)
        {
            prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
        }
        prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie)));
        prefsWriter.apply();
    }
    

    ここの論理は、まず彼のtokenを手に入れて、tokenはどのように構成されていますか?ドメイン名@CookieのKey例:127.0.0.1@key1 , 127.0.0.1@key2 , 127.0.0.1@key3
    Cookieが期限切れかどうかを判断します.
  • 期限が切れたら新しい空のmapを追加します.
  • 期限切れがなければ、Cookieに同じKeyのCookieが存在するか否かを判断し、存在する場合、removeは同じnameの古いcookieデータを消去する.

  • 実はここで問題があります.期限が切れていないときは、古いデータをremoveしてから、新しいデータを追加しなければなりません.はっきり言って、古いデータを上書きして、新しいデータをローカルに永続化しなければなりません.
    問題を解決する
    OK、問題が見つかりましたので、ここで彼のコードを修正します.
    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());
            }
            cookies.get(url.host()).put(name, cookie);
        } else
        {
            //          
            Map cookieMap = cookies.get(url.host());
            if (cookieMap != null)
            {
                cookieMap.put(name, cookie);
            }
        }
        // cookies      
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
        if (url.host() != null && cookies.get(url.host()) != null)
        {
            prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
        }
        prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie)));
        prefsWriter.apply();
    }
    

    ここでは最適化処理を行い,まずhost対応のcookieMapを取得し,空でなければ直接putを入れる.どうしてそうするの?ここではまずcookiesについて説明します.containsKey(url.host()この行のコードの意味は何ですか??mapにこのkeyが存在するかどうか、keyが存在する場合はtrueを返すという意味です.でもちょうどmapにnullが保存されていたら??mapではkey-valueの形式で、valueはnullに許可されています.
    だから私はここでまず対応するvalueを取得して、判断が空ではありませんて、更に対応する処理を行って、論理的に言えば、比較的に安全な1つの方法です.それから直接putに入って、keyと同じなら古いデータを上書きします.クッキーを永続化するローカルでは、これ以上言うことはありません.
    の最後の部分
    ここに貼って、私が修正したGitHubアドレスとGradle直接使用アドレス:GitHub:https://github.com/xiaolei123/OkHttpHelper Gradle : implementation 'com.xiaolei:OkHttpUtil:1.0.6'使用:
    com.xiaolei.okhttputil.Cookie.CookieJar cookiejar = new CookieJar(context,null);
    new OkHttpClient.Builder()
            .cookieJar(cookiejar)
            .build();
    

    The End