๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Retrofit2] Retrofit2์—์„œ ํƒ€์ž„์•„์›ƒ ๋ฐ ๋ฆฌํŠธ๋ผ์ด ์„ค์ •

์ถœ์ฒ˜

ChatGPT


Retrofit2์—์„œ ํƒ€์ž„์•„์›ƒ ๋ฐ ๋ฆฌํŠธ๋ผ์ด ์„ค์ •

1. OkHttpClient๋กœ ํƒ€์ž„์•„์›ƒ ์„ค์ •ํ•˜๊ธฐ

OkHttpClient๋Š” ์„ธ ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

  • ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ(connect timeout): ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์ตœ๋Œ€ ์‹œ๊ฐ„.
  • ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ(read timeout): ์„œ๋ฒ„์—์„œ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์ตœ๋Œ€ ์‹œ๊ฐ„.
  • ์“ฐ๊ธฐ ํƒ€์ž„์•„์›ƒ(write timeout): ์„œ๋ฒ„์— ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์ตœ๋Œ€ ์‹œ๊ฐ„.

๊ฐ๊ฐ์˜ ํƒ€์ž„์•„์›ƒ์€ ํŠน์ • ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.util.concurrent.TimeUnit;

public class ApiClient {

    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // OkHttpClient ์„ค์ •
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS) // ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                    .readTimeout(30, TimeUnit.SECONDS)    // ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                    .writeTimeout(30, TimeUnit.SECONDS)   // ์“ฐ๊ธฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                    .build();

            // Retrofit ์„ค์ •
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

 

 

์„ค๋ช…

 

  • connectTimeout: ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ๋•Œ์˜ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•œ๋‹ค.
  • readTimeout: ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ์˜ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•œ๋‹ค.
  • writeTimeout: ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ์˜ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•œ๋‹ค.
  • TimeUnit.SECONDS: ํƒ€์ž„์•„์›ƒ ์‹œ๊ฐ„์˜ ๋‹จ์œ„๋ฅผ ์„ค์ •ํ•œ๋‹ค. (TimeUnit.MILLISECONDS ๋“ฑ ๋‹ค๋ฅธ ๋‹จ์œ„๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
๋”๋ณด๊ธฐ

์ฝ”ํ‹€๋ฆฐ ์˜ˆ์ œ

import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

object ApiClient {

    private const val BASE_URL = "https://api.example.com/"
    private var retrofit: Retrofit? = null

    fun getClient(): Retrofit {
        if (retrofit == null) {
            // OkHttpClient ์„ค์ •
            val client = OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)  // ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                .readTimeout(30, TimeUnit.SECONDS)     // ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                .writeTimeout(30, TimeUnit.SECONDS)    // ์“ฐ๊ธฐ ํƒ€์ž„์•„์›ƒ: 30์ดˆ
                .build()

            // Retrofit ์„ค์ •
            retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofit!!
    }
}

 

2. ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜ ์„ค์ •

OkHttpClient๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์ง€๋งŒ, ์ด๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฆฌํŠธ๋ผ์ด ๊ธฐ๋Šฅ์€ Interceptor๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ฆฌํŠธ๋ผ์ด ์ธํ„ฐ์…‰ํ„ฐ ๊ตฌํ˜„

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class ApiClient {

    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // ๋ฆฌํŠธ๋ผ์ด ์ธํ„ฐ์…‰ํ„ฐ ๊ตฌํ˜„
            Interceptor retryInterceptor = new Interceptor() {
                private int maxRetry = 3;  // ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜ ์„ค์ •
                private int retryCount = 0;

                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Response response = null;
                    boolean responseOK = false;

                    while (!responseOK && retryCount < maxRetry) {
                        try {
                            response = chain.proceed(request);
                            responseOK = response.isSuccessful();
                        } catch (Exception e) {
                            retryCount++;
                            if (retryCount >= maxRetry) {
                                throw e;  // ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
                            }
                        }
                    }
                    return response;
                }
            };

            // OkHttpClient ์„ค์ •
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .addInterceptor(retryInterceptor)  // ๋ฆฌํŠธ๋ผ์ด ์ธํ„ฐ์…‰ํ„ฐ ์ถ”๊ฐ€
                    .build();

            // Retrofit ์„ค์ •
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

 

 

์„ค๋ช…

 

  • maxRetry: ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • retryCount: ํ˜„์žฌ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
  • response.isSuccessful(): ์‘๋‹ต์ด ์„ฑ๊ณต์ ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์„ฑ๊ณต์ ์ด์ง€ ์•Š์œผ๋ฉด ์žฌ์‹œ๋„๋ฅผ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.
  • chain.proceed(request): ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์ด ์‹คํŒจํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • throw e: ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
๋”๋ณด๊ธฐ

์ฝ”ํ‹€๋ฆฐ ์˜ˆ์ œ

import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.util.concurrent.TimeUnit

object ApiClient {

    private const val BASE_URL = "https://api.example.com/"
    private var retrofit: Retrofit? = null

    fun getClient(): Retrofit {
        if (retrofit == null) {
            // ๋ฆฌํŠธ๋ผ์ด ์ธํ„ฐ์…‰ํ„ฐ ๊ตฌํ˜„
            val retryInterceptor = Interceptor { chain ->
                val request = chain.request()
                var response: Response? = null
                var responseOK = false
                var tryCount = 0
                val maxRetry = 3  // ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜ ์„ค์ •

                while (!responseOK && tryCount < maxRetry) {
                    try {
                        response = chain.proceed(request)
                        responseOK = response.isSuccessful
                    } catch (e: IOException) {
                        tryCount++
                        if (tryCount >= maxRetry) {
                            throw e  // ์ตœ๋Œ€ ๋ฆฌํŠธ๋ผ์ด ํšŸ์ˆ˜๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
                        }
                    }
                }
                response!!
            }

            // OkHttpClient ์„ค์ •
            val client = OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(retryInterceptor)  // ๋ฆฌํŠธ๋ผ์ด ์ธํ„ฐ์…‰ํ„ฐ ์ถ”๊ฐ€
                .build()

            // Retrofit ์„ค์ •
            retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofit!!
    }
}

3. ์‚ฌ์šฉ์ž ์ง€์ • OKHttpClient ์‚ฌ์šฉํ•˜๊ธฐ

Retrofit2๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ,OkHttpClient๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•ด ํƒ€์ž„์•„์›ƒ๊ณผ ๋ฆฌํŠธ๋ผ์ด ์„ค์ •์„ ๋ณด๋‹ค ์„ธ๋ถ€์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class ApiClient {

    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // ์‚ฌ์šฉ์ž ์ง€์ • OkHttpClient
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .retryOnConnectionFailure(true)  // ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ ์ž๋™ ์žฌ์‹œ๋„
                    .build();

            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

 

 

๋”๋ณด๊ธฐ

์ฝ”ํ‹€๋ฆฐ ์˜ˆ์ œ

import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

object ApiClient {

    private const val BASE_URL = "https://api.example.com/"
    private var retrofit: Retrofit? = null

    fun getClient(): Retrofit {
        if (retrofit == null) {
            // ์‚ฌ์šฉ์ž ์ง€์ • OkHttpClient
            val client = OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)  // ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ ์ž๋™ ์žฌ์‹œ๋„
                .build()

            // Retrofit ์„ค์ •
            retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofit!!
    }
}

 

์„ค๋ช…

 

  • retryOnConnectionFailure(true): ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • OkHttpClient.Builder(): ์‚ฌ์šฉ์ž ์ง€์ • OkHttpClient ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ๋ถ€ ์„ค์ •์„ ํ•ฉ๋‹ˆ๋‹ค.

 

๊ฒฐ๋ก 

 

  • ํƒ€์ž„์•„์›ƒ ์„ค์ •: ์—ฐ๊ฒฐ, ์ฝ๊ธฐ, ์“ฐ๊ธฐ ํƒ€์ž„์•„์›ƒ์„ ๊ฐ๊ฐ ์„ค์ •ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋„คํŠธ์›Œํฌ ์ƒํ™ฉ์— ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋‹ค. OkHttpClient๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋ฆฌํŠธ๋ผ์ด ์„ค์ •: Interceptor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™ ๋ฆฌํŠธ๋ผ์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ง€์ • ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.