##やりたいこと
Retrofit2を使って通信をする時に、 「アクセストークンがあるかどうか」など状況に応じてヘッダーを付与する。
ただし、 @Headers
アノテーションは使わずに Interceptor
を使う。
##失敗したこと
OkHttop.builder
と Retrofit.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)
}
}