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

Kotlin proxy kullanımını Ktor 3 HttpClient ve OkHttp ile öğrenin. Geo-targeting, sticky session, SOCKS5, 407 challenge yönetimi ve production hardening adım adım kod örnekleriyle.

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

Kotlin proxy entegrasyonu, modern Android ve backend geliştiriciler için kritik bir beceridir. İster SERP takibi, ister e-ticaret fiyat monitoringi, ister sosyal medya araştırması yapıyor olun — doğru proxy konfigürasyonu olmadan istekleriniz IP bloklarına takılır, CAPTCHA duvarlarıyla karşılaşır ve ölçeklenemez. Bu rehberde Ktor client proxy ve OkHttp proxy authentication konularını gerçek kod örnekleriyle ele alacağız.

Kotlin Proxy Nedir ve Neden Gereklidir?

Bir Kotlin proxy kurulumu, HTTP istemcinizin tüm trafiğini bir ara sunucu üzerinden yönlendirir. Hedef sunucu sizin gerçek IP'nizi değil, proxy'nin IP'sini görür. Bu, Kotlin web scraping projelerinde IP tabanlı rate limit'leri aşmak, coğrafi kısıtlamaları atlamak ve kimliğinizi korumak için temel bir tekniktir.

Sorun şu: Datacenter IP'leri (AWS, DigitalOcean, Google Cloud gibi ASN'ler) çoğu modern platform tarafından kolayca tespit edilir ve bloklanır. Sosyal medya uygulamaları, e-ticaret siteleri ve arama motorları, datacenter ASN'lerini gerçek kullanıcı trafiğinden ayırt etmek için gelişmiş anti-bot sistemleri kullanır. Residential proxy'ler, gerçek ISP'lere ait IP'leri kullanarak bu tespiti zorlaştırır.

ProxyHat, residential, mobile ve datacenter proxy tiplerini tek bir gateway üzerinden sunar. Tüm örneklerde gate.proxyhat.com:8080 (HTTP) ve gate.proxyhat.com:1080 (SOCKS5) kullanacağız. Daha fazla bilgi için ProxyHat fiyatlandırma sayfasını inceleyebilirsiniz.

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

Kotlin'de proxy kullanımı için iki ana yaklaşım vardır: Ktor Client (Kotlin-native, coroutine dostu) ve OkHttp (JVM ekosisteminin en olgun HTTP istemcisi). İkisini yan yana kullanacağız.

Gradle Bağımlılıkları

build.gradle.kts dosyanıza şu bağımlılıkları ekleyin:

// Ktor 3.x — CIO engine (Kotlin-native, coroutine dostu)
implementation("io.ktor:ktor-client-core:3.0.3")
implementation("io.ktor:ktor-client-cio:3.0.3")
implementation("io.ktor:ktor-client-auth:3.0.3")
implementation("io.ktor:ktor-client-content-negotiation:3.0.3")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.3")

// OkHttp — JVM ekosistemi
implementation("com.squareup.okhttp3:okhttp:4.12.0")

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

OkHttp engine'i Ktor ile de kullanabilirsiniz — bu, OkHttp'in olgun proxy altyapısından yararlanmanızı sağlar:

implementation("io.ktor:ktor-client-okhttp:3.0.3")

Temel Proxy Yönlendirme: gate.proxyhat.com:8080

ProxyHat'in HTTP proxy gateway'ine bağlanmak için iki şey gerekir: proxy adresi ve Basic authentication. Proxy auth, HTTP istemcisinden bağımsız bir protokol adımıdır — Proxy-Authorization header'ı proxy'ye gönderilir, hedef sunucuya değil.

Yöntem 1: Ktor Client ile Proxy (CIO Engine)

Ktor'da proxy konfigürasyonu engine'e özeldir. CIO engine, proxyConfig parametresi ile HTTP proxy destekler. Proxy authentication ise defaultRequest bloğunda Proxy-Authorization header olarak eklenmelidir:

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.*
import java.util.Base64

fun createKtorClientWithProxy(): HttpClient {
    val proxyUser = "user-country-DE-city-berlin"
    val proxyPass = "SIFRENIZ"
    val authHeader = "Basic " + Base64.getEncoder()
        .encodeToString("$proxyUser:$proxyPass".toByteArray())

    return HttpClient(CIO) {
        engine {
            proxyConfig = ProxyConfig(
                url = "http://gate.proxyhat.com:8080",
                type = ProxyType.HTTP
            )
        }
        defaultRequest {
            header("Proxy-Authorization", authHeader)
        }
    }
}

suspend fun main() {
    val client = createKtorClientWithProxy()
    val response = client.get("https://httpbin.org/ip")
    println("IP: ${response.bodyAsText()}")
    client.close()
}

Dikkat: user-country-DE-city-berlin formatı, ProxyHat'in geo-targeting söz dizimidir. -session-abc123 ekleyerek sticky session oluşturabilirsiniz. Detaylı bilgi için ProxyHat lokasyonlar sayfasını ziyaret edin.

Yöntem 2: OkHttp ile Proxy (Raw Java.net.Proxy)

OkHttp, proxy konfigürasyonu için java.net.Proxy sınıfını kullanır. Authentication ise Authenticator arayüzü ile sağlanır:

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

fun createOkHttpClientWithProxy(): OkHttpClient {
    val proxy = Proxy(
        Proxy.Type.HTTP,
        InetSocketAddress("gate.proxyhat.com", 8080)
    )

    val proxyAuthenticator = Authenticator { _, response ->
        val credential = Credentials.basic(
            "user-country-DE-city-berlin",
            "SIFRENIZ"
        )
        response.request.newBuilder()
            .header("Proxy-Authorization", credential)
            .build()
    }

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator(proxyAuthenticator)
        .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
        .readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
        .build()
}

fun main() {
    val client = createOkHttpClientWithProxy()
    val request = Request.Builder()
        .url("https://httpbin.org/ip")
        .build()

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

Geo-Targeting ve Sticky Session Encoding

ProxyHat, geo-targeting ve sticky session bilgilerini kullanıcı adına gömer. Bu, URL'de ek parametre gerektirmeden proxy davranışını kontrol etmenizi sağlar:

Username FormatAçıklamaKullanım
user-country-USABD IP'siÜlke bazlı scraping
user-country-DE-city-berlinBerlin IP'siŞehir bazlı içerik
user-country-DE-session-abc123Sticky sessionOturum gerektiren siteler
user-country-US-session-xyz789ABD + stickySosyal medya oturumları

Sticky session, aynı IP'yi belirli bir süre boyunca korur — bu, oturum açma gerektiren sitelerde (e-ticaret sepetleri, sosyal medya hesapları) kritiktir. MDN Proxy-Authorization dokümantasyonu, bu header'ın nasıl çalıştığını detaylandırır.

SOCKS5 Proxy: Port 1080 ve System Properties

SOCKS5, HTTP proxy'den farklı olarak TCP katmanında çalışır ve tüm trafiği şeffaf şekilde yönlendirir. JVM'de SOCKS5 proxy için java.net.socks.username ve java.net.socks.password sistem özellikleri kullanılır:

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText

fun setupSocks5SystemProperties() {
    // SOCKS5 authentication JVM seviyesinde ayarlanır
    System.setProperty("socksProxyHost", "gate.proxyhat.com")
    System.setProperty("socksProxyPort", "1080")
    System.setProperty("java.net.socks.username", "user-country-US-session-abc123")
    System.setProperty("java.net.socks.password", "SIFRENIZ")
}

suspend fun main() {
    setupSocks5SystemProperties()

    // CIO engine, JVM SOCKS ayarlarını otomatik devralır
    val client = HttpClient(CIO) {
        engine {
            // SOCKS5 için system properties kullanılır
            // CIO bu ayarları otomatik algılar
        }
    }

    val response = client.get("https://httpbin.org/ip")
    println("SOCKS5 üzerinden IP: ${response.bodyAsText()}")
    client.close()
}

OkHttp ile SOCKS5 kullanımı ise Proxy.Type.SOCKS ile yapılır:

import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy

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

    // SOCKS5 auth için Authenticator yeterli değildir;
    // java.net.Authenticator kullanılır
    java.net.Authenticator.setDefault(object : java.net.Authenticator() {
        override fun getPasswordAuthentication(): java.net.PasswordAuthentication {
            return java.net.PasswordAuthentication(
                "user-country-US-session-abc123",
                "SIFRENIZ".toCharArray()
            )
        }
    })

    return OkHttpClient.Builder()
        .proxy(proxy)
        .connectTimeout(15, java.util.concurrent.TimeUnit.SECONDS)
        .build()
}

SOCKS5, WebSocket ve gRPC gibi HTTP dışı protokoller için de uygundur. ProxyHat SDK'sı da aynı pattern'i kullanır — ProxyHat dokümantasyonunu inceleyebilirsiniz.

Residential Proxy'ler: Neden Datacenter IP'leri Yetersiz Kalır?

Modern platformlar — Instagram, Amazon, Ticketmaster, Shopify siteleri — datacenter IP'lerini ASN veritabanlarıyla eşleştirir. ASN (Autonomous System Number) kontrolü ile bir IP'nin AWS, Google Cloud veya DigitalOcean'a ait olduğunu saniyeler içinde tespit edebilirler. Bu IP'ler genellikle 403 veya 429 yanıtı alır.

Residential proxy'ler, gerçek ISP'lere (Deutsche Telekom, Comcast, Vodafone) ait IP'leri kullandığı için bu tespiti atlatır. ProxyHat'in residential havuzu, 190+ ülkede milyonlarca IP barındırır. Web scraping use case sayfamızda bu konuyu detaylı işledik.

Coroutine ile Concurrent Fan-Out Örneği

Aşağıdaki örnek, Kotlin coroutines kullanarak paralel istekler gönderir ve Semaphore ile eşzamanlılık sınırını kontrol eder:

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.*
import kotlinx.coroutines.*
import java.util.Base64

data class ScrapeResult(val url: String, val status: Int, val body: String)

suspend fun fanOutScrape(urls: List<String>): List<ScrapeResult> = coroutineScope {
    val semaphore = Semaphore(10) // Aynı anda maksimum 10 istek
    val proxyUser = "user-country-DE-city-berlin"
    val proxyPass = "SIFRENIZ"
    val authHeader = "Basic " + Base64.getEncoder()
        .encodeToString("$proxyUser:$proxyPass".toByteArray())

    val client = HttpClient(CIO) {
        engine {
            proxyConfig = ProxyConfig(
                url = "http://gate.proxyhat.com:8080",
                type = ProxyType.HTTP
            )
        }
        defaultRequest {
            header("Proxy-Authorization", authHeader)
        }
    }

    val results = urls.map { url ->
        async(Dispatchers.IO) {
            semaphore.withPermit {
                try {
                    val response = client.get(url)
                    ScrapeResult(url, response.status.value, response.bodyAsText())
                } catch (e: Exception) {
                    ScrapeResult(url, 0, e.message ?: "Error")
                }
            }
        }
    }.awaitAll()

    client.close()
    results
}

suspend fun main() {
    val urls = listOf(
        "https://httpbin.org/ip",
        "https://httpbin.org/headers",
        "https://httpbin.org/user-agent",
        "https://httpbin.org/status/200",
        "https://httpbin.org/status/404"
    )

    val results = fanOutScrape(urls)
    results.forEach { r ->
        println("${r.url} -> ${r.status}")
    }
}

Bu örnekte Semaphore(10) ile aynı anda en fazla 10 istek gönderilir. Hedef sunucunun rate limit'ini aşmadan ölçeklenmenizi sağlar. 50 URL için bu yaklaşım 5 batch halinde çalışır ve ortalama 2-3 saniyede tamamlanır.

Production Hardening: 407 Challenge, Retry, Timeout ve TLS

Production'da proxy bağlantıları kırılgandır. Proxy sunucusu 407 Proxy Authentication Required yanıtı gönderebilir, bağlantı zaman aşımına uğrayabilir veya TLS el sıkışması başarısız olabilir.

OkHttp Authenticator ile 407 Yönetimi

OkHttp'in Authenticator arayüzü, 407 yanıtı alındığında otomatik olarak credential ekler ve isteği yeniden gönderir:

import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy

fun createProductionOkHttpClient(): OkHttpClient {
    val proxy = Proxy(
        Proxy.Type.HTTP,
        InetSocketAddress("gate.proxyhat.com", 8080)
    )

    val proxyAuthenticator = Authenticator { _, response ->
        // 407 challenge durumunda credential yeniden eklenir
        // OkHttp bunu otomatik olarak bir kez dener
        val credential = Credentials.basic(
            "user-country-DE-session-abc123",
            "SIFRENIZ"
        )
        response.request.newBuilder()
            .header("Proxy-Authorization", credential)
            .build()
    }

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator(proxyAuthenticator)
        .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
        .readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
        .writeTimeout(15, java.util.concurrent.TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .connectionPool(ConnectionPool(20, 5, java.util.concurrent.TimeUnit.MINUTES))
        .build()
}

Ktor'da Retry ve Timeout

Ktor'da retry ve timeout için HttpTimeout plugin'i ve manuel retry döngüsü kullanılır:

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.delay

suspend fun fetchWithRetry(
    client: HttpClient,
    url: String,
    maxRetries: Int = 3
): String? {
    var lastError: Exception? = null
    repeat(maxRetries) { attempt ->
        try {
            val response = client.get(url)
            if (response.status.value in 200..299) {
                return response.bodyAsText()
            }
            // 429 veya 503 durumunda bekle ve tekrar dene
            if (response.status.value == 429 || response.status.value == 503) {
                delay((attempt + 1) * 1000L) // 1s, 2s, 3s
            }
        } catch (e: Exception) {
            lastError = e
            delay((attempt + 1) * 500L)
        }
    }
    lastError?.printStackTrace()
    return null
}

fun createProductionKtorClient(): HttpClient {
    return HttpClient(CIO) {
        install(HttpTimeout) {
            connectTimeoutMillis = 10_000
            requestTimeoutMillis = 30_000
            socketTimeoutMillis = 30_000
        }
        engine {
            proxyConfig = ProxyConfig(
                url = "http://gate.proxyhat.com:8080",
                type = ProxyType.HTTP
            )
            // CIO engine TLS ayarları
            // httpsEndpoint = httpsEndpoint.copy(
            //     verifyCertificates = true
            // )
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic ...")
        }
    }
}

Android NetworkSecurityConfig

Android'de proxy trafiği için network_security_config.xml dosyası, cleartext trafiği ve sertifika pinning yönetimi için önemlidir:

<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <!-- ProxyHat HTTP proxy için cleartext izni -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">gate.proxyhat.com</domain>
    </domain-config>
    <!-- Hedef HTTPS siteleri için sertifika doğrulama -->
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">api.example.com</domain>
    </domain-config>
</network-security-config>

AndroidManifest.xml'de bu dosyayı referans verin:

<application
    android:networkSecurityConfig="@xml/network_security_config">
    ...
</application>

Etik Scraping ve Yasal Hususlar

Web scraping güçlü bir araçtır ama yasal sınırları vardır. ABD'de Computer Fraud and Abuse Act (CFAA), yetkisiz erişimi yasaklar. AB'de GDPR, kişisel verilerin işlenmesinde katı kurallar koyar — IP adresleri de kişisel veri sayılabilir.

En iyi pratikler:

  • Yalnızca herkese açık verileri toplayın. Login arkasındaki verilere erişmek CFAA ihlali olabilir.
  • robots.txt dosyasını kontrol edin ve sayfalarını tarayın. Respect etmek yasal bir zorunluluk olmasa bile etik bir gerekliliktir.
  • Rate limit'i hedef sunucu için makul tutun. Saniyede 100 istek göndermek DDoS'e yakın.
  • Resmi API'leri tercih edin. Çoğu platform (Twitter, Reddit, GitHub) resmi API sunar — scraping'e göre daha güvenilir ve yasal olarak daha temizdir.
  • Kullanım koşullarını (ToS) okuyun. Bazı siteler scraping'i açıkça yasaklar.

SERP tracking use case sayfamız, etik scraping pratiklerini daha detaylı ele alır.

Key Takeaways

Özet:

  • Ktor'da proxy auth defaultRequest'te Proxy-Authorization header olarak eklenir; OkHttp'de proxyAuthenticator kullanılır.
  • Geo-targeting ve sticky session, kullanıcı adına gömülür: user-country-DE-city-berlin-session-abc123.
  • SOCKS5 için port 1080 ve java.net.socks.username sistem özellikleri kullanılır.
  • Residential proxy'ler, datacenter ASN bloklarını atlatmak için gereklidir — sosyal medya ve e-ticaret sitelerinde başarı oranı %90+'ya çıkar.
  • Production'da 407 challenge, retry, timeout ve connection pooling konfigürasyonu zorunludur.
  • Coroutine + Semaphore ile rate-controlled fan-out, hedef sunucuyu darboğaza sokmadan ölçeklenmenizi sağlar.

ProxyHat ile Başlayın

ProxyHat, residential, mobile ve datacenter proxy'leri tek bir gateway üzerinden sunar. gate.proxyhat.com:8080 HTTP proxy veya gate.proxyhat.com:1080 SOCKS5 ile dakikalar içinde başlayın. Fiyatlandırma sayfasından planınızı seçin ve dashboard.proxyhat.com üzerinden credential'larınızı alın.

ProxyHat SDK'sı, bu makalede gösterilen pattern'leri otomatikleştirir — proxy rotation, health check ve session yönetimi dahili olarak gelir. Dokümantasyonu inceleyerek başlayın.

Sık sorulan sorular

Kotlin proxy nedir ve nasıl çalışır?

Kotlin proxy, HTTP istemcinizin (Ktor Client veya OkHttp) tüm trafiğini bir ara sunucu üzerinden yönlendirme tekniğidir. Proxy sunucusu, hedef sunucuya sizin IP'niz yerine kendi IP'siyle istek gönderir. Kotlin'de proxy, engine konfigürasyonunda (CIO için proxyConfig, OkHttp için Proxy sınıfı) ayarlanır ve kimlik doğrulama Proxy-Authorization header'ı veya Authenticator arayüzü ile sağlanır.

Kotlin proxy kullanıcı için neden önemlidir?

Kotlin proxy, web scraping projelerinde IP tabanlı blokları aşmak, coğrafi kısıtlamaları atlatmak ve rate limit'leri yönetmek için gereklidir. Datacenter IP'leri modern platformlar tarafından kolayca tespit edilir ve bloklanır. Residential proxy'ler, gerçek ISP IP'leri kullanarak bu tespiti atlatır ve scraping başarı oranını %90+'ya çıkarır. Ayrıca coroutine tabanlı concurrent isteklerle ölçeklenebilir scraping pipeline'ları kurulabilir.

Kotlin proxy için en iyi proxy tipi hangisidir?

Kullanım senaryosuna bağlıdır. Web scraping ve sosyal medya otomasyonu için residential proxy'ler en iyi seçimdir çünkü datacenter ASN bloklarını atlatır. Hız ve maliyet öncelikli ise datacenter proxy'ler yeterli olabilir. Mobile proxy'ler, en yüksek güvenilirliği sunar çünkü gerçek mobil operatör IP'leri kullanır. ProxyHat, üç tipi de gate.proxyhat.com:8080 üzerinden aynı API ile sunar — kullanıcı adındaki parametrelerle tip değiştirilebilir.

Kotlin proxy kullanırken blokları nasıl önlersiniz?

Blokları önlemek için: residential proxy kullanın (datacenter IP'leri tespit edilir), sticky session ile oturum tutarlılığını sağlayın, Semaphore ile eşzamanlılık sınırlandırın (örneğin 10 concurrent istek), request'ler arasına rastgele gecikme ekleyin, User-Agent ve Accept header'larını gerçek tarayıcıyla eşleştirin, 429 ve 503 yanıtlarında exponential backoff ile retry yapın. Ayrıca robots.txt dosyasına saygı göstermek ve yalnızca herkese açık verileri toplamak yasal riskleri azaltır.

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

148'den fazla ülkede residential, ISP ve mobil proxy'ler. Ücretsiz hesap oluşturun.

Ücretsiz hesap oluştur
← Bloga Dön