Kotlin'de Proxy Kullanımı: Ktor ve OkHttp ile Geliştirici Rehberi

Kotlin'de proxy kullanımı için Ktor Client ve OkHttp ile residential proxy yapılandırmasını, geo-targeting, sticky session, SOCKS5 ve production hardening adımlarını kod örnekleriyle öğrenin.

Using Proxies in Kotlin: A Code-First Guide with Ktor and OkHttp

Kotlin'de Proxy Kullanımı: Ktor ve OkHttp ile Pratik Rehber

Android uygulamanız veya Kotlin backend servisiniz veri toplamaya çalışırken aniden 403 veya 429 hataları almaya başladıysanız, yalnız değilsiniz. Birçok web ve API hedefi, datacenter IP aralıklarını ASN düzeyinde engeller; bu da Kotlin'de proxy kullanımı konusunu bir tercih değil, bir zorunluluk haline getirir. Bu rehberde Ktor 3 HttpClient ve OkHttp ile residential proxy'leri nasıl yapılandıracağınızı, geo-targeting ve sticky session'ları nasıl uygulayacağınızı ve production-grade hata yönetimini nasıl kuracağınızı adım adım göstereceğiz.

İster Kotlin web scraping yapan bir otomasyon aracı, ister sosyal medya araştırma platformu geliştiriyor olun, proxy yönlendirme ve kimlik doğrulama detayları projenizin başarısını doğrudan etkiler. Aşağıdaki örnekler ProxyHat'ın gate.proxyhat.com:8080 HTTP gateway'i ve :1080 SOCKS5 port'u üzerinden residential proxy'lere bağlanmak için tasarlanmıştır.

Teknik Bağlam: Neden Residential Proxy Gerekir?

Datacenter proxy'ler düşük gecikme ve düşük maliyet sunar, ancak günümüz anti-bot sistemleri IP'lerin ASN'sini kontrol eder ve AWS, Google Cloud, Azure gibi bilinen bulut sağlayıcı aralıklarını otomatik olarak işaretler. Cloudflare ve benzeri WAF sağlayıcıları, datacenter ASN'lerinden gelen istekleri sık sık challenge'a sokar veya tamamen engeller.

Residential proxy'ler ise gerçek ISP'lere ait IP adresleri kullandığı için hedef sunucu açısından normal bir kullanıcı gibi görünür. Bu, özellikle sosyal medya platformları, e-ticaret siteleri ve mobil API'ler için kritik bir fark yaratır. ProxyHat'ın residential ağı, ProxyHat dokümantasyonunda detaylandırıldığı gibi 190+ ülkede IP havuzlarına sahiptir ve mevcut lokasyonlar arasında ülke ve şehir düzeyinde hedefleme sunar.

Daha fazla bilgi için MDN'nin Proxy-Authorization başlık dokümantasyonuna başvurabilirsiniz.

Proje Kurulumu: Ktor 3 ve OkHttp Bağımlılıkları

Gradle tabanlı projenizde hem Ktor Client hem de OkHttp kullanmak için aşağıdaki bağımlılıkları ekleyin. Ktor 3.x, Kotlin 2.x ile çalışır ve CIO, OkHttp, Darwin gibi birden fazla engine destekler.

// build.gradle.kts
val ktorVersion = "3.0.3"
val okhttpVersion = "4.12.0"

dependencies {
    // Ktor Client - CIO engine (JVM backend için)
    implementation("io.ktor:ktor-client-core:$ktorVersion")
    implementation("io.ktor:ktor-client-cio:$ktorVersion")
    implementation("io.ktor:ktor-client-auth:$ktorVersion")
    implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
    implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")

    // OkHttp (Android ve JVM)
    implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")

    // Coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
}

Android projeleri için ktor-client-android veya ktor-client-okhttp engine'ini kullanabilirsiniz. Backend projelerinde CIO engine, coroutine tabanlı yapısıyla yüksek eşzamanlılık sağlar.

Ktor Client ile Proxy Yapılandırması

Ktor'da proxy kimlik doğrulaması engine'e özeldir ve defaultRequest bloğunda Proxy-Authorization başlığını manuel olarak eklemeniz gerekir. Aşağıdaki örnekte ProxyHat gateway'ine bağlanıyor, ülke ve şehir düzeyinde geo-targeting uyguluyor ve sticky session oluşturuyoruz.

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.runBlocking
import java.util.Base64

fun createKtorClient(
    country: String = "DE",
    city: String = "berlin",
    sessionId: String = "abc123"
): HttpClient {
    // Proxy kimlik bilgileri - geo-targeting ve sticky session username'e gömülür
    val proxyUser = "user-country-$country-city-$city-session-$sessionId"
    val proxyPass = "YOUR_PASSWORD"
    val authHeader = "Basic " + Base64.getEncoder()
        .encodeToString("$proxyUser:$proxyPass".toByteArray())

    return HttpClient(CIO) {
        engine {
            proxy = ProxyBuilder.http("gate.proxyhat.com", 8080)
        }
        defaultRequest {
            headers.append("Proxy-Authorization", authHeader)
        }
        // Timeout ayarları
        install(HttpTimeout) {
            connectTimeoutMillis = 10_000
            requestTimeoutMillis = 30_000
        }
    }
}

fun main() = runBlocking {
    val client = createKtorClient(country = "DE", city = "berlin")
    val response: HttpResponse = client.get("https://httpbin.org/ip")
    println("Status: ${response.status.value}")
    println("Body: ${response.bodyAsText()}")
    client.close()
}

Dikkat edin: Proxy-Authorization başlığı her istekte otomatik eklenir. Farklı ülkeler için ayrı client instance'ları oluşturabilir veya sessionId'yi dinamik olarak değiştirebilirsiniz. ProxyHat fiyatlandırması sayfasından planınızı kontrol edebilirsiniz.

OkHttp ile Raw Proxy Yapılandırması

OkHttp, java.net.Proxy sınıfı üzerinden HTTP proxy'leri destekler. Proxy kimlik doğrulaması için bir Authenticator kaydetmeniz gerekir; bu, 407 Proxy Authentication Required challenge'ına otomatik yanıt verir.

import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.Base64
import java.util.concurrent.TimeUnit

fun createOkHttpClient(
    country: String = "US",
    city: String = "",
    sessionId: String = ""
): OkHttpClient {
    // Username'e geo-targeting ve session flag gömülür
    val username = buildString {
        append("user-country-$country")
        if (city.isNotEmpty()) append("-city-$city")
        if (sessionId.isNotEmpty()) append("-session-$sessionId")
    }
    val password = "YOUR_PASSWORD"
    val credentials = Credentials.basic(username, password)

    val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator { _, response ->
            // 407 challenge'ına Proxy-Authorization ile yanıt ver
            response.request.newBuilder()
                .header("Proxy-Authorization", credentials)
                .build()
        }
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .build()
}

fun main() {
    val client = createOkHttpClient(country = "US", sessionId = "sess-001")
    val request = Request.Builder()
        .url("https://httpbin.org/ip")
        .build()

    client.newCall(request).execute().use { response ->
        println("Code: ${response.code}")
        println("Body: ${response.body?.string()}")
    }
}

Ktor ve OkHttp Proxy Desteği Karşılaştırması

ÖzellikKtor Client (CIO)OkHttp
Proxy kimlik doğrulamadefaultRequest ile manuel başlıkAuthenticator ile otomatik 407 yanıtı
SOCKS5 desteğiEngine bağımlı (JVM system properties)java.net.Proxy(Type.SOCKS) ile native
Coroutine entegrasyonuNative (suspend fonksiyonlar)Call.execute() bloklayıcı; wrapper gerekir
Android uyumluluğuOkHttp engine ile evetNative evet
Connection poolingEngine yönetirConnectionPool ile yapılandırılabilir

SOCKS5 Proxy: Port 1080 ile Bağlantı

SOCKS5, HTTP proxy'den farklı olarak uygulama katmanı yerine taşıma katmanında çalışır ve TCP trafiğini şeffaf şekilde tünelleyebilir. ProxyHat SOCKS5 erişimi için gate.proxyhat.com:1080 adresini kullanır. JVM'de SOCKS5 kimlik doğrulaması, system properties üzerinden yapılır.

// SOCKS5 proxy için JVM system properties
// Uygulama başlangıcında veya programatik olarak ayarlayın

fun configureSocks5Proxy() {
    // SOCKS5 proxy adresi
    System.setProperty("socksProxyHost", "gate.proxyhat.com")
    System.setProperty("socksProxyPort", "1080")

    // SOCKS5 kimlik doğrulama (java.net.socks namespace)
    System.setProperty("java.net.socks.username", "user-country-FR-session-xyz789")
    System.setProperty("java.net.socks.password", "YOUR_PASSWORD")
}

// OkHttp ile SOCKS5 kullanımı (alternatif yöntem)
import java.net.Proxy
import java.net.InetSocketAddress

fun createSocks5OkHttp(): OkHttpClient {
    val socksProxy = Proxy(
        Proxy.Type.SOCKS,
        InetSocketAddress("gate.proxyhat.com", 1080)
    )

    return OkHttpClient.Builder()
        .proxy(socksProxy)
        .proxyAuthenticator { _, response ->
            val creds = Credentials.basic(
                "user-country-FR-session-xyz789",
                "YOUR_PASSWORD"
            )
            response.request.newBuilder()
                .header("Proxy-Authorization", creds)
                .build()
        }
        .build()
}

Not: SOCKS5 system properties tüm JVM bağlantılarını etkiler. Mikro-service mimarisinde sadece belirli istekleri SOCKS5 üzerinden yönlendirmek için OkHttp'nin Proxy parametresini kullanmanız önerilir.

Residential Proxy'lerle Eşzamanlı İstek Dağıtımı

Sosyal medya platformları ve e-ticaret siteleri, tek bir IP'den gelen yüksek hacimli istekleri engeller. Residential proxy'ler ile farklı IP'lerden eşzamanlı istek göndererek hız sınırlarını aşabilirsiniz. Aşağıdaki örnekte Kotlin coroutines ile async/awaitAll kullanarak fan-out yapıyor ve Semaphore ile eşzamanlılık sayısını kontrol ediyoruz.

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.withSemaphore
import java.util.Base64
import java.util.UUID

suspend fun fetchWithProxy(
    client: HttpClient,
    url: String
): Result<String> {
    return runCatching {
        val response = client.get(url)
        if (response.status.value in 200..299) {
            response.bodyAsText()
        } else {
            throw Exception("HTTP ${response.status.value}")
        }
    }
}

suspend fun fanOutRequests(
    urls: List<String>,
    maxConcurrency: Int = 20
): List<Result<String>> = coroutineScope {
    val semaphore = Semaphore(maxConcurrency)

    // Her istek için benzersiz session ID → farklı residential IP
    val deferreds = urls.map { url ->
        async(Dispatchers.IO) {
            semaphore.withPermit {
                val sessionId = UUID.randomUUID().toString().take(8)
                val proxyUser = "user-country-DE-session-$sessionId"
                val authHeader = "Basic " + Base64.getEncoder()
                    .encodeToString("$proxyUser:YOUR_PASSWORD".toByteArray())

                val client = HttpClient(CIO) {
                    engine {
                        proxy = ProxyBuilder.http("gate.proxyhat.com", 8080)
                    }
                    defaultRequest {
                        headers.append("Proxy-Authorization", authHeader)
                    }
                    install(HttpTimeout) {
                        connectTimeoutMillis = 10_000
                        requestTimeoutMillis = 30_000
                    }
                }

                try {
                    fetchWithProxy(client, url)
                } finally {
                    client.close()
                }
            }
        }
    }

    deferreds.awaitAll()
}

fun main() = runBlocking {
    val urls = (1..100).map { "https://httpbin.org/delay/1?id=$it" }
    val results = fanOutRequests(urls, maxConcurrency = 20)

    val successCount = results.count { it.isSuccess }
    val failCount = results.count { it.isFailure }
    println("Başarılı: $successCount, Başarısız: $failCount")
}

Bu örnekte her istek için benzersiz bir sessionId oluşturulur; bu, ProxyHat'ın her isteği farklı bir residential IP'ye yönlendirmesini sağlar. Semaphore(20) ile aynı anda en fazla 20 istek aktif kalır, böylece hedef sunucunun hız limitlerini tetiklemezsiniz. Web scraping kullanım senaryosu sayfamızda bu pattern'in gerçek dünya uygulamalarını inceleyebilirsiniz.

Production Hardening: Hata Yönetimi ve TLS Yapılandırması

Production ortamında proxy bağlantıları çeşitli nedenlerle başarısız olabilir: 407 kimlik doğrulama hataları, bağlantı zaman aşımları, TLS el sıkışma sorunları ve IP rotasyonu sırasındaki geçici kesintiler. Aşağıdaki örnekte OkHttp için kapsamlı bir production yapılandırması görüyorsunuz.

import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import java.security.KeyStore

fun createProductionOkHttp(): OkHttpClient {
    val username = "user-country-US-city-newyork-session-prod-001"
    val password = "YOUR_PASSWORD"
    val credentials = Credentials.basic(username, password)

    // TLS yapılandırması
    val trustManagerFactory = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm()
    )
    trustManagerFactory.init(null as KeyStore?)
    val trustManagers = trustManagerFactory.trustManagers
    val x509TrustManager = trustManagers.filterIsInstance<X509TrustManager>().first()

    val sslContext = SSLContext.getInstance("TLSv1.3")
    sslContext.init(null, arrayOf(x509TrustManager), null)

    val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator { _, response ->
            if (response.code == 407) {
                response.request.newBuilder()
                    .header("Proxy-Authorization", credentials)
                    .build()
            } else null
        }
        .sslSocketFactory(sslContext.socketFactory, x509TrustManager)
        .connectionPool(ConnectionPool(
            maxIdleConnections = 20,
            keepAliveDuration = 5,
            TimeUnit.MINUTES
        ))
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .callTimeout(60, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .build()
}

// Retry + Circuit breaker pattern (basit implementasyon)

class ProxyRetryHandler(
    private val client: OkHttpClient,
    private val maxRetries: Int = 3,
    private val backoffMs: Long = 1000L
) {
    fun executeWithRetry(request: Request): Response {
        var attempt = 0
        var lastException: Exception? = null

        while (attempt < maxRetries) {
            try {
                val response = client.newCall(request).execute()
                if (response.code !in 500..599 && response.code != 429) {
                    return response
                }
                response.close()
            } catch (e: Exception) {
                lastException = e
            }
            attempt++
            Thread.sleep(backoffMs * attempt) // Linear backoff
        }
        throw lastException ?: Exception("Max retries exceeded")
    }
}

Android için NetworkSecurityConfig

Android 9 (API 28) ve sonrasında cleartext trafik varsayılan olarak engellidir. ProxyHat HTTP gateway'i ile TLS kullandığınızda sorun yaşamazsınız, ancak geliştirme sırasında res/xml/network_security_config.xml dosyasında doğru yapılandırma gerekebilir:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">gate.proxyhat.com</domain>
    </domain-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

ProxyHat SDK'sı da benzer bir pattern izler: username içine geo-targeting ve session flag'leri gömer, Proxy-Authorization başlığını otomatik ekler ve 407 challenge'larına retry uygular. SDK kullanımı, manuel yapılandırma hatalarını azaltır ancak bu rehberdeki raw yöntemler, SDK'nin arka planda ne yaptığını anlamanız için değerlidir.

Etik Veri Toplama ve Yasal Çerçeve

Proxy kullanımı teknik bir konudur, ancak yasal ve etik sınırları da içerir. ABD'de Computer Fraud and Abuse Act (CFAA), yetkisiz erişimi yasaklar; Avrupa Birliği'nde GDPR, kişisel verilerin toplanmasını sıkı kurallara bağlar. Her zaman hedef sitenin robots.txt dosyasını kontrol etmeli ve mümkün olduğunda resmi API'leri tercih etmelisiniz.

İyi uygulamalar:

  • Yalnızca herkese açık verileri toplayın; kimlik doğrulama gerektiren sayfaları otomatik taramayın.
  • Hedef sunucuya aşırı yük bindirmemek için istek hızınızı sınırlayın (örneğin saniyede 5 istek).
  • Kişisel veriler (GDPR kapsamında) topluyorsanız yasal dayanağınız olduğundan emin olun.
  • Hedef platformun Terms of Service şartlarını okuyun ve saygı gösterin.
  • Resmi API mevcutsa scraping yerine API'yi tercih edin — daha kararlı ve yasal olarak daha güvenli.

SERP tracking kullanım senaryosu ve web scraping kullanım senaryosu sayfalarımızda etik veri toplama ile ilgili daha fazla pratik öneri bulabilirsiniz.

Key Takeaways

  • Ktor Client'da proxy auth manuel'dir: defaultRequest bloğunda Proxy-Authorization: Basic başlığını kendiniz eklemelisiniz; engine otomatik yapmaz.
  • OkHttp'de Authenticator kullanın: 407 challenge'larına otomatik yanıt verir ve retry mekanizması sunar.
  • Geo-targeting username'e gömülür: user-country-DE-city-berlin-session-abc123 formatı ProxyHat'ın tüm proxy tiplerinde aynı çalışır.
  • Residential proxy'ler datacenter engellerini aşar: Sosyal medya ve e-ticaret siteleri datacenter ASN'lerini engeller; residential IP'ler normal kullanıcı gibi görünür.
  • Semaphore ile eşzamanlılık kontrolü: Coroutine fan-out pattern'inde Semaphore kullanarak hedef sunucunun rate limit'lerini tetiklemeden yüksek hacimli istekler gönderin.
  • Production'da retry + backoff şart: 407, 429 ve 5xx hataları için retry mekanizması, linear veya exponential backoff ile birlikte kullanın.
  • SOCKS5 için port 1080: HTTP proxy'den farklı olarak system properties veya Proxy.Type.SOCKS ile yapılandırın.
  • Etik scraping: Herkese açık verilerle sınırlı kalın, robots.txt'e saygı gösterin ve resmi API'leri tercih edin.

SSS

Proxy kullanımı ile ilgili sık sorulan sorular için aşağıdaki FAQ bölümüne bakın. Daha fazla teknik detay için ProxyHat dokümantasyonunu inceleyebilir veya fiyatlandırma sayfamızdan plan seçebilirsiniz.

Başlamaya hazır mısınız?

148+ ülkede 50M+ konut IP'sine AI destekli filtreleme ile erişin.

Fiyatlandırmayı GörüntüleKonut Proxy'leri
← Bloga Dön