Android okHttpブロック要求ヘッダと応答ヘッダ

6988 ワード

まず、ここをクリックするオープンソースプロジェクトをお勧めします.
これは網易クラウド音楽UIに基づいて、Gankを使用している.Ioおよび豆弁apiが開発したGoogle Material Designに準拠したAndroidオープンソースプロジェクト.プロジェクトはMVVM-DataBindingアーキテクチャの開発を採用し、現在は主に乾物区、映画区、書籍区の3つのサブモジュールを含む.
私もこのオープンソースプロジェクトを見て、新しいプロジェクトフレームワークがMVVM DataBindingとRetrofitを使用することを決定しました.
無私に奉仕してくれた人々に感謝します.
Retrofitとbindingに関する知識もたくさん出てきたので、私は恥をかかせません.
次に私が出会った問題を話します.
新しいプロジェクトのネットの要求、白私は長い間慕っていたRetrofitを使いました.
プロジェクトで使用されるjarは、上のオープンソースフレームワークで使用されます.
compile 'com.jakewharton.retrofit:retrofit1-okhttp3-client:1.1.0'

先日、ログインに成功したときに返されるコードをネットワークリクエストのヘッダに挿入し、バックグラウンドで認証する必要がありました.検証に失敗すると401が戻る.
この需要はよく知られていません.以前はプロジェクトのほとんどがありました.
そこで調べてみると、okhttpclient builderオブジェクトを初期化したとき、restAdapterオブジェクトとしたときにリクエストブロックを挿入するという考え方が明確になっています.
注:下に貼る方法の一つは私が最初に試した方法で、実現することができますが、面倒なので、皆さんは考え方の参考にして、後で改善した簡単な方法を貼ることができます.
次はOkhttpClient.Builderオブジェクトの初期化時にブロッキングを挿入し、ネットワーク要求がresponseに戻ったときにブロッキングヘッダがcookiesを取り出して自分で保存します.
okBuilder.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {

                Response originalResponse = chain.proceed(chain.request());

                    if (!originalResponse.headers("Set-Cookie").isEmpty()) {
                        HashSet cookies = new HashSet();

                        for (String header : originalResponse.headers("Set-Cookie")) {
                            cookies.add(header);
                            Log.v("OkHttp", "save Header: " + header);
                        }

                        //      cookies
                    }

                return originalResponse;
            }
        });
次はブロック要求requestであり,上に保存したcookiesをrequestのヘッダに自分で入れる.この操作はRestAdapterに置いた.Builderオブジェクト初期化中(addでinterceptorを1つ入れることもできます).
builder.setRequestInterceptor(new RequestInterceptor() {
            @Override
            public void intercept(RequestFacade request) {
                        HashSet preferences = //       cookies
                        for (String cookie : preferences) {
                            request.addHeader("Cookie", cookie);
                            Log.v("OkHttp", "Adding Header: " + cookie);
                        }
            }
        });

プロジェクトを実行して、インタフェースは200に戻って、楽しくタバコを吸って冷静になりました.抽完回来再运行401了!!!また試して、時には401、時には200.
Nパスをチェックし、ログインに成功して返されたcookiesとリクエスト時にheadのcookiesを挿入します.大丈夫ですよ.
この問題は朝9時に座ってパソコンに向かって夜9時までです.無数の予想を出した.
最後の推測を直接言います:上のコードに保存されているcookiesはHashSetを使用しています.無秩序が原因だと思います.同僚たちはこの問題だと信じていない.しかし、私は募集していないので、やってみましょう.
そこでHashSetをArrayListに変更しました.
できました.本当にこの問題です.(一生ハシュセットは使いたくない気がします)
上は私がプロジェクトの中で、見つけた解決方法ですが、いつも変な感じがして、それから私はまた資料を調べて試して、比較的便利な方法を見つけました.
注:次の2つのクラスはkotlinの言語で書かれています(javaと互換性があり、知らない学生は勉強しなければなりません).
次に、リクエストヘッダのcookiesをブロックし、キャッシュに直接保存します.
package com.reliable.mihophysical.api

import android.content.Context
import android.text.TextUtils

import java.io.IOException
import java.util.HashSet

import okhttp3.Interceptor
import okhttp3.Response

/**
 *         
 * Created by ge
 */

class SaveCookiesInterceptor(private val mContext: Context) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)
        //set-cookie     
        if (!response.headers("set-cookie").isEmpty()) {
            val cookies = response.headers("set-cookie")
            val cookie = encodeCookie(cookies)
            saveCookie(request.url().toString(), request.url().host(), cookie)
        }

        return response
    }

    //  cookie      
    private fun encodeCookie(cookies: List): String {
        val sb = StringBuilder()
        val set = HashSet()
        for (cookie in cookies) {
            val arr = cookie.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            for (s in arr) {
                if (set.contains(s)) continue
                set.add(s)

            }
        }

        val ite = set.iterator()
        while (ite.hasNext()) {
            val cookie = ite.next()
            sb.append(cookie).append(";")
        }

        val last = sb.lastIndexOf(";")
        if (sb.length - 1 == last) {
            sb.deleteCharAt(last)
        }

        return sb.toString()
    }

    //  cookie   ,        url host     cookie,  host  
    //      cookie       
    private fun saveCookie(url: String, domain: String, cookies: String) {
        val sp = mContext.getSharedPreferences(COOKIE_PREF, Context.MODE_PRIVATE)
        val editor = sp.edit()

        if (TextUtils.isEmpty(url)) {
            throw NullPointerException("url is null.")
        } else {
            editor.putString(url, cookies)
        }

        if (!TextUtils.isEmpty(domain)) {
            editor.putString(domain, cookies)
        }

        editor.apply()

    }

    companion object {

        private val COOKIE_PREF = "cookies_prefs"
    }
}

次に、リクエストヘッダのcookiesを追加するクラスです.
package com.reliable.mihophysical.api

import android.content.Context
import android.text.TextUtils

import java.io.IOException

import okhttp3.Interceptor
import okhttp3.Response

/**
 *         
 * Created by ge 
 */

class AddCookiesInterceptor(private val mContext: Context) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val builder = request.newBuilder()
        val cookie = getCookie(request.url().toString(), request.url().host())
        if (!TextUtils.isEmpty(cookie)) {
            builder.addHeader("Cookie", cookie!!)
        }

        return chain.proceed(builder.build())
    }

    private fun getCookie(url: String, domain: String): String? {
        val sp = mContext.getSharedPreferences(COOKIE_PREF, Context.MODE_PRIVATE)
        if (!TextUtils.isEmpty(url) && sp.contains(url) && !TextUtils.isEmpty(sp.getString(url, ""))) {
            return sp.getString(url, "")
        }
        if (!TextUtils.isEmpty(domain) && sp.contains(domain) && !TextUtils.isEmpty(sp.getString(domain, ""))) {
            return sp.getString(domain, "")
        }

        return null
    }

    companion object {

        private val COOKIE_PREF = "cookies_prefs"
    }
}

最後にokhttpのbuilderを構築するときも、次のようにします.
//        
        okBuilder.addInterceptor(AddCookiesInterceptor(context!!))
        okBuilder.addInterceptor(SaveCookiesInterceptor(context!!))

これにより、最初に述べたように、手動でcookiesを探して保存し、取り出して手動で追加する必要はありません.