Utiliser des proxies en Kotlin : guide complet avec Ktor et OkHttp

Guide développeur pour configurer des proxies résidentiels, datacenter et mobiles en Kotlin avec Ktor Client et OkHttp. Geo-targeting, sessions sticky, SOCKS5, authentification proxy et hardening production inclus.

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

Si vous développez des scrapers, des clients API ou des applications Android en Kotlin, vous avez probablement rencontré des blocages IP, des erreurs 403 ou des CAPTCHAs inattendus. Utiliser des proxies en Kotlin est la solution pour distribuer vos requêtes à travers plusieurs adresses IP, contourner les limites de taux et accéder à des contenus géo-restreints. Ce guide pratique vous montre comment configurer Ktor Client et OkHttp avec des proxies résidentiels, datacenter et mobiles — avec du code exécutable à chaque étape.

Pourquoi utiliser des proxies en Kotlin ?

Les serveurs web modernes utilisent des systèmes anti-bot sophistiqués qui analysent l'adresse IP source, les en-têtes HTTP, le fingerprint TLS et le comportement de navigation. Quand vous envoyez des centaines de requêtes depuis une seule IP, ces systèmes déclenchent des blocages, des CAPTCHAs ou des réponses 429 (Too Many Requests).

Un proxy agit comme un intermédiaire : votre client Kotlin se connecte au proxy, qui relaie la requête vers la cible. L'IP vue par le serveur cible est celle du proxy, pas la vôtre. En rotant à travers un pool de proxies résidentiels, vous distribuez vos requêtes sur des centaines d'IPs différentes, rendant chaque requête indiscernable du trafic d'un utilisateur réel.

Le Kotlin web scraping nécessite donc une stratégie proxy adaptée à la cible. Voici une comparaison des trois types de proxies disponibles chez ProxyHat :

Type de proxy Avantages Inconvénients Cas d'usage typique
Résidentiel IPs d'ISP réelles, faible détection, ~99.9% de succès sur cibles strictes Latence ~200ms supérieure vs datacenter, coût plus élevé SERP scraping, réseaux sociaux, e-commerce
Datacenter Rapide (<50ms), économique, idéal pour haut volume ASNs facilement détectables par les anti-bots APIs publiques, tests, monitoring interne
Mobile Détection quasi nulle, IPs 4G/5G d'opérateurs Le plus coûteux, latence variable Cibles très strictes, comptes sensibles

Pour approfondir les cas d'usage, consultez notre guide sur le web scraping avec proxies et le tracking SERP.

Configuration du projet — Ktor Client et OkHttp

Kotlin offre deux clients HTTP majeurs pour le scraping : Ktor Client (multiplateforme, coroutine-native) et OkHttp (standard Android/JVM). Les deux supportent les proxies HTTP et SOCKS5, mais l'API diffère.

Dépendances Gradle

Pour un projet Kotlin/JVM ou Android, ajoutez ces dépendances dans votre build.gradle.kts :

// Ktor 3.x avec moteur CIO (Coroutine-based, pas de dépendance native)
implementation("io.ktor:ktor-client-core:3.0.3")
implementation("io.ktor:ktor-client-cio:3.0.3")

// OkHttp 4.x (standard Android/JVM)
implementation("com.squareup.okhttp3:okhttp:4.12.0")

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

Le moteur CIO de Ktor est purement Kotlin, basé sur coroutines, et ne nécessite aucune dépendance native. Il supporte les proxies HTTP via java.net.Proxy.

Ktor HttpClient avec proxy HTTP

Configuration basique d'un Ktor client proxy sur le port 8080 :

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import java.net.InetSocketAddress
import java.net.Proxy

val client = HttpClient(CIO) {
    engine {
        proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
    }
}

// Test basique
val response: HttpResponse = client.get("https://httpbin.org/ip")
println(response.bodyAsText())
client.close()

OkHttp avec proxy — baseline

Configuration équivalente avec OkHttp :

import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.InetSocketAddress
import java.net.Proxy

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

val client = OkHttpClient.Builder()
    .proxy(proxy)
    .build()

val request = Request.Builder()
    .url("https://httpbin.org/ip")
    .build()

client.newCall(request).execute().use { response ->
    if (response.isSuccessful) {
        println(response.body?.string())
    }
}

Sans authentification, ces deux exemples échoueront avec une erreur 407 Proxy Authentication Required. C'est là que les choses deviennent intéressantes.

Routage via gate.proxyhat.com : geo-targeting et sessions sticky

ProxyHat encode le geo-targeting et les sessions sticky directement dans le nom d'utilisateur. Le format est user-country-XX-city-YYYY-session-ZZZ. L'authentification proxy se fait via l'en-tête Proxy-Authorization: Basic, mais comme l'authentification proxy est spécifique au moteur HTTP, Ktor ne l'envoie pas automatiquement — il faut l'ajouter manuellement dans defaultRequest.

Voici un exemple complet avec geo-targeting (Allemagne, Berlin) et session sticky :

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 java.net.InetSocketAddress
import java.net.Proxy
import java.util.Base64

// Geo-targeting: Allemagne, Berlin + session sticky
val username = "user-country-DE-city-berlin-session-abc123"
val password = "your-password"
val credentials = Base64.getEncoder()
    .encodeToString("$username:$password".toByteArray())

val client = HttpClient(CIO) {
    engine {
        proxy = Proxy(
            Proxy.Type.HTTP,
            InetSocketAddress("gate.proxyhat.com", 8080)
        )
    }
    defaultRequest {
        header("Proxy-Authorization", "Basic $credentials")
        header("User-Agent", "Mozilla/5.0 (compatible; MyBot/1.0)")
    }
}

val response: HttpResponse = client.get("https://httpbin.org/headers")
println(response.bodyAsText())
client.close()

Points clés du geo-targeting :

  • user-country-DE — route via une IP allemande
  • city-berlin — cible une IP à Berlin (plus précis, légèrement plus lent)
  • session-abc123 — sticky session : toutes les requêtes utilisent la même IP tant que la session est active

Sans le flag session, ProxyHat attribue une nouvelle IP à chaque requête (rotation per-request). Pour du scraping SERP où vous devez paginer des résultats, la session sticky est essentielle pour maintenir la cohérence de l'IP source. Consultez les docs ProxyHat pour la liste complète des paramètres supportés.

Le SDK ProxyHat reproduit ce même pattern : il construit l'URL du proxy avec les flags geo/session dans le username et injecte l'en-tête Proxy-Authorization automatiquement. En Kotlin, vous pouvez soit utiliser le SDK, soit reproduire ce pattern manuellement comme ci-dessus.

SOCKS5 sur le port 1080

Le protocole SOCKS5 opère au niveau TCP, ce qui le rend utile pour les connexions non-HTTP (WebSockets, gRPC, connexions brutes). ProxyHat expose SOCKS5 sur le port 1080.

En JVM, l'approche la plus simple pour OkHttp proxy authentication en SOCKS5 consiste à utiliser les propriétés système java.net.socks.username et java.net.socks.password :

import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.InetSocketAddress
import java.net.Proxy

// Configuration SOCKS5 via propriétés système
System.setProperty("socksProxyHost", "gate.proxyhat.com")
System.setProperty("socksProxyPort", "1080")
System.setProperty("java.net.socks.username", "user-country-FR")
System.setProperty("java.net.socks.password", "your-password")

val client = OkHttpClient.Builder()
    .proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("gate.proxyhat.com", 1080)))
    .build()

val request = Request.Builder()
    .url("https://httpbin.org/ip")
    .build()

client.newCall(request).execute().use { response ->
    println(response.body?.string())
}

Attention : les propriétés système sont globales à la JVM. En Android ou dans un service multi-tenant, préférez l'authentification par en-tête Proxy-Authorization avec HTTP sur le port 8080 pour éviter les conflits.

Proxies résidentiels pour cibles sociales et applicatives

Les plateformes sociales (Instagram, Twitter/X, LinkedIn) et les apps e-commerce détectent et bloquent les ASNs datacenter (AWS, Google Cloud, DigitalOcean) en quelques requêtes. Les proxies résidentiels utilisent des IPs d'ISP réelles (Orange, Comcast, Vodafone), ce qui rend le trafic indiscernable d'un utilisateur normal.

Pour du Kotlin web scraping à grande échelle, vous devez combiner proxies résidentiels, rotation de sessions et contrôle de concurrence. Voici un exemple complet utilisant les coroutines Kotlin avec async/awaitAll et un Semaphore pour limiter le parallélisme à 100 requêtes concurrentes :

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.Base64

suspend fun scrapeConcurrent(
    urls: List<String>,
    maxConcurrency: Int = 100
): List<Result<String>> {
    val semaphore = Semaphore(maxConcurrency)
    val credentials = Base64.getEncoder()
        .encodeToString("user-country-US:your-password".toByteArray())

    val client = HttpClient(CIO) {
        engine {
            proxy = Proxy(
                Proxy.Type.HTTP,
                InetSocketAddress("gate.proxyhat.com", 8080)
            )
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic $credentials")
        }
    }

    return coroutineScope {
        urls.map { url ->
            async(Dispatchers.IO) {
                semaphore.withPermit {
                    try {
                        val resp = client.get(url)
                        Result.success(resp.bodyAsText())
                    } catch (e: Exception) {
                        Result.failure(e)
                    }
                }
            }
        }.awaitAll()
    }.also { client.close() }
}

Pourquoi le Semaphore ? Sans contrôle de concurrence, async lance toutes les coroutines simultanément. Sur 10 000 URLs, cela créerait 10 000 connexions simultanées — le proxy rejeterait la plupart. Le Semaphore(100) garantit qu'au maximum 100 requêtes sont en vol à tout moment.

Rotation per-request vs sticky : sans le flag session, ProxyHat attribue une nouvelle IP résidentielle à chaque requête. C'est idéal pour le scraping massif. Pour les sessions de connexion (login + navigation), utilisez session-xxx pour garder la même IP pendant toute la session.

Hardening production — Authenticator, retries, TLS

En production, plusieurs problèmes surviennent : expirations de session proxy, timeouts réseau, challenges 407 inattendus, et pools de connexions saturés. Voici une configuration OkHttp durcie avec proxyAuthenticator pour gérer les 407, timeouts explicites, et pool de connexions :

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

val username = "user-country-US-session-mySession01"
val password = "your-password"
val credentials = Base64.getEncoder()
    .encodeToString("$username:$password".toByteArray())

// Authenticator pour les challenges 407 Proxy Authentication Required
val proxyAuth = Authenticator { _, response ->
    if (response.code == 407) {
        response.request.newBuilder()
            .header("Proxy-Authorization", "Basic $credentials")
            .build()
    } else null
}

val client = OkHttpClient.Builder()
    .proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080)))
    .proxyAuthenticator(proxyAuth)
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(15, TimeUnit.SECONDS)
    .retryOnConnectionFailure(true)
    .connectionPool(ConnectionPool(20, 5, TimeUnit.MINUTES))
    .build()

val request = Request.Builder()
    .url("https://httpbin.org/ip")
    .header("User-Agent", "Mozilla/5.0 (compatible; MyBot/1.0)")
    .build()

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

Détails de configuration :

  • connectTimeout(10s) — évite de bloquer indéfiniment si le proxy ne répond pas
  • readTimeout(30s) — les cibles lentes (pages lourdes, APIs lentes) ont besoin de marge
  • ConnectionPool(20, 5min) — 20 connexions keep-alive, 5 minutes de TTL. Réduit la latence de connexion de ~200ms à ~0ms sur les requêtes répétées
  • retryOnConnectionFailure(true) — OkHttp retente automatiquement les échecs réseau
  • proxyAuthenticator — gère les challenges 407 en réinjectant l'en-tête Proxy-Authorization

Configuration TLS

Par défaut, Ktor et OkHttp utilisent la configuration TLS de la JVM. Pour éviter les erreurs de certificat avec certains proxies, vous pouvez explicitement configurer un TrustManager standard :

import okhttp3.OkHttpClient
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager

// ATTENTION: à n'utiliser qu'en dev/test. En production,
// gardez la validation TLS par défaut de la JVM.
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
    override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {}
    override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}
    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
})

val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())

val client = OkHttpClient.Builder()
    .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
    .hostnameVerifier { _, _ -> true }
    .build()

En production, ne désactivez jamais la validation TLS. ProxyHat utilise des certificats valides sur gate.proxyhat.com. La configuration ci-dessus est uniquement pour le débogage.

Note Android : NetworkSecurityConfig

Sur Android 9+ (API 28+), le trafic HTTP en clair est bloqué par défaut. Pour autoriser la connexion au proxy (qui est en HTTP, pas HTTPS), ajoutez un network_security_config.xml :

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">gate.proxyhat.com</domain>
    </domain-config>
</network-security-config>

Puis référencez-le dans le AndroidManifest.xml :

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

Cela autorise uniquement le trafic en clair vers gate.proxyhat.com tout en gardant le HTTPS obligatoire pour le reste. Le tunnel proxy lui-même est en HTTP, mais le trafic entre le proxy et la cible reste chiffré en HTTPS.

Considérations éthiques et légales

Le scraping web n'est pas illégal per se, mais il opère dans une zone grise. Voici les principes à respecter :

  • Données publiques uniquement. Ne scrapez que des pages accessibles sans authentification. Accéder à des données derrière un login sans autorisation peut violer le Computer Fraud and Abuse Act (CFAA) aux États-Unis ou des lois équivalentes en Europe.
  • GDPR dans l'UE. Le scraping de données personnelles (noms, emails, photos) est soumis au Règlement Général sur la Protection des Données (RGPD). Vous devez avoir une base légale pour chaque traitement.
  • Respectez robots.txt et les conditions d'utilisation. Un robots.txt n'est pas juridiquement contraignant, mais l'ignorer renforce l'argument de « accès non autorisé » dans une procédure judiciaire.
  • Préférez les APIs officielles. Si une plateforme offre une API (Twitter API, Google Custom Search, Amazon Product Advertising), utilisez-la. Le scraping doit être un dernier recours.
  • Limitez votre impact. Ne submergez pas les serveurs cibles. Un délai de 1 à 5 secondes entre les requêtes est une bonne pratique. Le Semaphore ci-dessus limite la concurrence ; ajoutez des delay() pour espacer les requêtes.

Pour les tarifs des différents types de proxies, consultez notre page de tarification.

Points clés à retenir

Utiliser des proxies en Kotlin se résume à quatre étapes : (1) configurer le proxy dans le moteur HTTP (Ktor CIO ou OkHttp), (2) ajouter l'en-tête Proxy-Authorization: Basic avec les credentials encodés, (3) encoder le geo-targeting et les sessions sticky dans le username, et (4) contrôler la concurrence avec Semaphore et async/awaitAll. Pour la production, ajoutez un proxyAuthenticator OkHttp pour gérer les 407, des timeouts explicites, et un pool de connexions. Préférez les proxies résidentiels pour les cibles strictes, datacenter pour le volume, et mobile pour les anti-bots les plus agressifs.

FAQ

Qu'est-ce que l'utilisation de proxies en Kotlin ?

L'utilisation de proxies en Kotlin consiste à router les requêtes HTTP ou SOCKS5 d'une application Kotlin (backend, Android ou multiplateforme) via un serveur intermédiaire. Avec Ktor Client, on configure le proxy au niveau du moteur (CIO, OkHttp, etc.) via java.net.Proxy. Avec OkHttp, on utilise OkHttpClient.Builder().proxy(...). L'authentification se fait via l'en-tête Proxy-Authorization: Basic ou les propriétés système SOCKS.

Pourquoi utiliser des proxies en Kotlin est-il important ?

Les systèmes anti-bot modernes bloquent les IPs datacenter, limitent le débit par IP, et servent du contenu géo-restreint. Sans proxy, un scraper Kotlin envoyant 1000 requêtes depuis une seule IP sera bloqué en quelques minutes. Les proxies résidentiels distribuent le trafic sur des IPs d'ISP réelles, contournant ces limitations et offrant un taux de succès de ~99.9% sur les cibles strictes comme les SERP Google ou les réseaux sociaux.

Quel type de proxy fonctionne le mieux en Kotlin ?

Cela dépend de la cible. Les proxies résidentiels sont idéaux pour les plateformes sociales, le SERP scraping et l'e-commerce (IPs d'ISP, faible détection). Les proxies datacenter sont plus rapides (<50ms) et économiques, adaptés aux APIs publiques et aux tests. Les proxies mobiles (4G/5G) offrent la détection la plus faible mais au coût le plus élevé. Pour la plupart des projets de scraping en Kotlin, commencez par des résidentiels avec rotation per-request.

Comment éviter les blocages avec des proxies en Kotlin ?

Utilisez des proxies résidentiels ou mobiles (jamais datacenter pour les cibles strictes), rottez les sessions via le flag session-xxx de ProxyHat, limitez la concurrence avec Semaphore (max 50 à 100 requêtes simultanées), ajoutez des délais aléatoires de 1 à 5 secondes entre les requêtes, configurez des en-têtes réalistes (User-Agent, Accept-Language), et implémentez des retries avec backoff exponentiel. Respectez toujours robots.txt et les conditions d'utilisation de la cible.

Questions fréquentes

Qu'est-ce que l'utilisation de proxies en Kotlin ?

L'utilisation de proxies en Kotlin consiste à router les requêtes HTTP ou SOCKS5 d'une application Kotlin (backend, Android ou multiplateforme) via un serveur intermédiaire. Avec Ktor Client, on configure le proxy au niveau du moteur (CIO, OkHttp) via java.net.Proxy. Avec OkHttp, on utilise OkHttpClient.Builder().proxy(...). L'authentification se fait via l'en-tête Proxy-Authorization: Basic ou les propriétés système SOCKS.

Pourquoi utiliser des proxies en Kotlin est-il important ?

Les systèmes anti-bot modernes bloquent les IPs datacenter, limitent le débit par IP, et servent du contenu géo-restreint. Sans proxy, un scraper Kotlin envoyant 1000 requêtes depuis une seule IP sera bloqué en quelques minutes. Les proxies résidentiels distribuent le trafic sur des IPs d'ISP réelles, contournant ces limitations et offrant un taux de succès d'environ 99.9% sur les cibles strictes comme les SERP Google ou les réseaux sociaux.

Quel type de proxy fonctionne le mieux en Kotlin ?

Cela dépend de la cible. Les proxies résidentiels sont idéaux pour les plateformes sociales, le SERP scraping et l'e-commerce (IPs d'ISP, faible détection). Les proxies datacenter sont plus rapides (moins de 50ms) et économiques, adaptés aux APIs publiques et aux tests. Les proxies mobiles (4G/5G) offrent la détection la plus faible mais au coût le plus élevé. Pour la plupart des projets de scraping en Kotlin, commencez par des résidentiels avec rotation per-request.

Comment éviter les blocages avec des proxies en Kotlin ?

Utilisez des proxies résidentiels ou mobiles (jamais datacenter pour les cibles strictes), rottez les sessions via le flag session-xxx de ProxyHat, limitez la concurrence avec Semaphore (max 50 à 100 requêtes simultanées), ajoutez des délais aléatoires de 1 à 5 secondes entre les requêtes, configurez des en-têtes réalistes (User-Agent, Accept-Language), et implémentez des retries avec backoff exponentiel. Respectez toujours robots.txt et les conditions d'utilisation de la cible.

Prêt à commencer ?

Proxys résidentiels, ISP et mobiles dans plus de 148 pays. Créez un compte gratuit.

Créer un compte gratuit
← Retour au Blog