DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Retrofit Interceptor完全ガイド — 認証/ログ/リトライ/キャッシュ

この記事で学べること

Retrofit Interceptor(認証ヘッダー、ログ出力、リトライ、キャッシュ制御)を解説します。


認証Interceptor

class AuthInterceptor @Inject constructor(
    private val tokenManager: TokenManager
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val token = tokenManager.getAccessToken()
        val request = chain.request().newBuilder()
            .addHeader("Authorization", "Bearer $token")
            .addHeader("Accept", "application/json")
            .build()

        val response = chain.proceed(request)

        // 401の場合トークンリフレッシュ
        if (response.code == 401) {
            response.close()
            val newToken = runBlocking { tokenManager.refreshToken() }
            val newRequest = chain.request().newBuilder()
                .addHeader("Authorization", "Bearer $newToken")
                .build()
            return chain.proceed(newRequest)
        }

        return response
    }
}
Enter fullscreen mode Exit fullscreen mode

リトライInterceptor

class RetryInterceptor(private val maxRetries: Int = 3) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var attempt = 0
        var lastException: IOException? = null

        while (attempt < maxRetries) {
            try {
                val response = chain.proceed(chain.request())
                if (response.isSuccessful || response.code !in listOf(500, 502, 503)) {
                    return response
                }
                response.close()
            } catch (e: IOException) {
                lastException = e
            }

            attempt++
            if (attempt < maxRetries) {
                Thread.sleep(1000L * attempt)  // 指数バックオフ
            }
        }

        throw lastException ?: IOException("Max retries exceeded")
    }
}
Enter fullscreen mode Exit fullscreen mode

OkHttpClient構築

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideOkHttpClient(
        authInterceptor: AuthInterceptor
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(authInterceptor)
            .addInterceptor(RetryInterceptor(maxRetries = 3))
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
                else HttpLoggingInterceptor.Level.NONE
            })
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}
Enter fullscreen mode Exit fullscreen mode

まとめ

Interceptor 用途
認証 Authorization Header
ログ HttpLoggingInterceptor
リトライ 指数バックオフ
キャッシュ Cache-Control
  • Interceptorでリクエスト/レスポンスを横断的に処理
  • 認証トークンの自動付与とリフレッシュ
  • リトライInterceptorで一時的なエラーに対応
  • HttpLoggingInterceptorでデバッグ時のみログ出力

8種類のAndroidアプリテンプレート(ネットワーク設計済み)を公開しています。

テンプレート一覧Gumroad

関連記事:


I publish 8 Android app templates (Room DB, Material3, MVVM) on Gumroad.

Browse templatesGumroad

Top comments (0)