9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Retrofit2のIntercepterを使ってヘッダーをつける(Kotlin)

Posted at

##やりたいこと

Retrofit2を使って通信をする時に、 「アクセストークンがあるかどうか」など状況に応じてヘッダーを付与する。

ただし、 @Headersアノテーションは使わずに Interceptor を使う。

##失敗したこと

OkHttop.builderRetrofit.Builder は共通インスタンスで持っておいて、 後からOkHttop.builderにInterceptorを追加しようとしたらダメでした。


    /**
     * 認証ヘッダーなしのサービスクラス
     */
    val mDataSource: HogeServiceClass by lazy {
        val authClient = mClientBuilder.build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }

    /**
     * 認証ヘッダーありのサービスクラス
     * 後からインターセプターを追加しても反映されず、失敗
     */
    val mAuthDataSource : HogeServiceClass by lazy{
        // Interseptorを追加
        val authClient = mClientBuilder.addInterceptor(mInterceptor).build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }


OkHttpClient maintains a list of the interceptors which you can access, however it is an unmodifiable collection.
https://stackoverflow.com/a/47394293/8800049

とのことで、どうやらOkHttpClientは一度インスタンス化してしまうと後からInterceptor自体を追加することは出来ないようです。

ダメだったコード全体は最下部に書いてます。

OkHttpClientのインスタンスをもう一個別に作ればうまく行きますが、なんかスマートじゃない。
そもそもサービスクラスのインスタンスを二つ作って使い分けるのもスマートじゃない。

解決策

Interceptorの定義内で条件分岐することで簡単に解決しました。


    private val mInterceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()

            if(this.accessToken.isNotEmpty()){
                chain.proceed(
                        original.newBuilder()
                                .header("Authorization", this.accessToken)
                                .method(original.method(), original.body())
                                .build()
                )
            }else{
                chain.proceed(
                        original.newBuilder()
                                .method(original.method(), original.body())
                                .build()
                )
            }
        }
    }

こうすることで、サービスクラスは一つで良いし、スッキリしました。

以下のようにアクセストークンを一度セットすれば、以降の通信は自動で全部認証のヘッダーが付与されます。

ServiceGenerator.accessToken = "hogehoge"

成功したコード全体


import com.facebook.stetho.okhttp3.StethoInterceptor
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import jp.co.jp.co.hoge.foo.HogeServiceClass
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory


object ServiceGenerator
{
    val moshi by lazy {
        Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()
    }

    var accessToken: String = ""

    private val mInterceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()

            //アクセストークンがあればヘッダーに付与
            if(this.accessToken.isNotEmpty()){
                chain.proceed(
                        original.newBuilder()
                                .header("Authorization", this.accessToken)
                                .method(original.method(), original.body())
                                .build()
                )
            }
            //それ以外はヘッダーを付与しない
            else{
                chain.proceed(
                        original.newBuilder()
                                .method(original.method(), original.body())
                                .build()
                )
            }
        }
    }

    private val mClient by lazy {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY

        OkHttpClient.Builder()
                .addInterceptor(mInterceptor)
                .addInterceptor(logging)
                .addNetworkInterceptor(StethoInterceptor())
                .build()
    }

    private val mRetrofit by lazy {
        Retrofit.Builder()
                .baseUrl(BuildConfig.API_BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .client(mClient)
                .build()
    }

    val mDataSource by lazy {
        mRetrofit.create(HogeServiceClass::class.java)
    }
}

##ダメだったコード全体

import com.facebook.stetho.okhttp3.StethoInterceptor
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import jp.co.jp.co.hoge.foo.HogeServiceClass
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory


object ServiceGenerator
{
    val moshi by lazy {
        Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()
    }

    var accessToken: String = ""


    private val mInterceptor: Interceptor by lazy {
        Interceptor { chain ->
            val original = chain.request()
            chain.proceed(
                    original.newBuilder()
                            .header("Authorization", this.accessToken)
                            .method(original.method(), original.body())
                            .build()
            )
        }
    }

    private val mClientBuilder: OkHttpClient.Builder by lazy {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY

        OkHttpClient.Builder()
                .addInterceptor(logging)
                .addNetworkInterceptor(StethoInterceptor())
    }

    private val mRetrofitBuilder: Retrofit.Builder by lazy{
        Retrofit.Builder()
                .baseUrl(BuildConfig.API_BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
    }

    /**
     * 認証ヘッダーなしのサービスクラス
     */
    val mDataSource: HogeServiceClass by lazy {
        val authClient = mClientBuilder.build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }

    /**
     * 認証ヘッダーありのサービスクラス
     * 後からインターセプターを追加しても反映されず、失敗
     */
    val mAuthDataSource : HogeServiceClass by lazy{
        val authClient = mClientBuilder.addInterceptor(mInterceptor).build()
        val mRetrofit = mRetrofitBuilder.client(authClient).build()
        mRetrofit.create(HogeServiceClass::class.java)
    }
}

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?