HTTP-Client in Kotlin: Anfragen richtig stellen – Fortgeschrittenes Niveau
Bei der Entwicklung moderner Anwendungen in Kotlin geht die Arbeit mit HTTP-Anfragen weit über den einfachen Aufruf von URL.readText() hinaus. Auf fortgeschrittenem Niveau müssen Verbindungsverwaltung, Timeouts, Wiederholungsversuche, Protokollierung, Asynchronität und korrekte Fehlerbehandlung berücksichtigt werden. In diesem Artikel werden wir uns ansehen, wie man einen HTTP-Client in Kotlin für eine Produktionsumgebung konfiguriert, unter Verwendung von zwei beliebten Bibliotheken: OkHttp und Ktor Client. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen von Kotlin und HTTP vertraut sind.
1. Bibliotheksauswahl: OkHttp vs Ktor Client
Bevor wir Code schreiben, ist es wichtig, den Unterschied zwischen den Ansätzen zu verstehen. OkHttp ist eine ausgereifte, bewährte Bibliothek von Square, die hervorragend mit Retrofit zusammenarbeitet. Ktor Client ist eine native plattformübergreifende Bibliothek von JetBrains, die vollständig in Kotlin-Coroutinen integriert ist. Für Serverprojekte mit Spring Boot wird oft OkHttp gewählt, während für Ktor-Anwendungen oder plattformübergreifende Projekte Ktor Client bevorzugt wird.
Wir werden beide Optionen betrachten, damit Sie die für Ihren Stack passende auswählen können.
2. Fortgeschrittene Konfiguration von OkHttp
Die Basiskonfiguration von OkHttp ist trivial, aber für die Produktion ist eine fein abgestimmte Konfiguration erforderlich. Betrachten wir die Erstellung eines Singleton-Clients mit benutzerdefinierten Parametern.
import okhttp3.*import java.util.concurrent.TimeUnit
object HttpClientProvider {
private val client: OkHttpClient by lazy { OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .addInterceptor(LoggingInterceptor()) .addInterceptor(RetryInterceptor(maxRetries = 3)) .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES)) .build() }
fun getClient(): OkHttpClient = client}2.1 Benutzerdefinierte Interceptors
Interceptors sind ein leistungsstarker Mechanismus zur Modifikation von Anfragen und Antworten. Nachfolgend finden Sie ein Beispiel für einen Protokollierungs-Interceptor und einen Interceptor für Wiederholungsversuche.
class LoggingInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() println("--> ${request.method} ${request.url}") val startTime = System.nanoTime() val response = chain.proceed(request) val duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) println("<-- ${response.code} ${response.message} (${duration}ms)") return response }}
class RetryInterceptor(private val maxRetries: Int) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var retryCount = 0 var response: Response? = null while (retryCount < maxRetries) { try { response = chain.proceed(chain.request()) if (response.isSuccessful) return response } catch (e: Exception) { println("Wiederholung #${retryCount + 1} fehlgeschlagen: ${e.message}") } retryCount++ if (retryCount < maxRetries) Thread.sleep(1000L * retryCount) } return response ?: throw IOException("Maximale Anzahl an Wiederholungen überschritten") }}2.2 Asynchrone Anfragen mit Coroutinen
OkHttp unterstützt synchrone und asynchrone (callback-basierte) Anfragen. Für die Integration mit Kotlin-Coroutinen verwenden wir suspendCancellableCoroutine.
suspend fun makeRequest(url: String): String { return suspendCancellableCoroutine { continuation -> val request = Request.Builder().url(url).build() val call = HttpClientProvider.getClient().newC