Se você está construindo um scraper, um cliente de API ou um app Android que precisa acessar dados de fontes externas, cedo ou tarde vai esbarrar em bloqueios por IP. Usar proxies em Kotlin é a forma mais direta de distribuir suas requisições por múltiplos endereços e evitar rate limits, CAPTCHAs e banimentos por ASN. Este guia mostra como configurar proxies residenciais e datacenter com Ktor Client 3 e OkHttp, com exemplos executáveis e padrões de produção.
Por que usar proxies em Kotlin com Ktor Client e OkHttp
Quando você faz uma requisição HTTP a partir de um servidor ou dispositivo, o IP de origem revela seu provedor de hospedagem. Sites de e-commerce, redes sociais e motores de busca mantêm listas de ASNs datacenter (AWS, Google Cloud, DigitalOcean) e aplicam limites agressivos — frequentemente bloqueando após 50–200 requisições por minuto. Proxies residenciais resolvem isso porque roteiam o tráfego por IPs de ISPs reais, tornando cada requisição indistinguível do tráfego orgânico.
No ecossistema Kotlin, duas bibliotecas dominam o acesso HTTP: OkHttp, amplamente usada no Android e em backends JVM, e Ktor Client, multiplataforma e idiomática com coroutines. Ambas suportam proxies, mas a configuração difere — OkHttp usa java.net.Proxy diretamente, enquanto Ktor depende do engine subjacente (CIO, OkHttp, Darwin) e exige cuidado com autenticação.
| Aspecto | OkHttp | Ktor Client (OkHttp engine) | Ktor Client (CIO engine) |
|---|---|---|---|
| Configuração de proxy | OkHttpClient.Builder().proxy() | engine { proxy = ... } | Propriedades de sistema ou ProxySelector |
| Autenticação proxy | Authenticator nativo | Authenticator do OkHttp | Header Proxy-Authorization manual |
| Suporte SOCKS5 | Sim (Proxy.Type.SOCKS) | Sim | Sim via System.setProperty |
| Multiplataforma | JVM/Android | JVM/Android | Todas as plataformas Ktor |
Configuração do projeto: dependências e baseline
Para começar, adicione as dependências no build.gradle.kts. Se você está no Android, use implementation; em um backend JVM, implementation também funciona com o catálogo de versões.
// build.gradle.kts
val ktorVersion = "3.0.3"
val okhttpVersion = "4.12.0"
dependencies {
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
implementation("io.ktor:ktor-client-cio:$ktorVersion")
implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
}
O exemplo mais simples com OkHttp define um java.net.Proxy apontando para o gateway da ProxyHat na porta 8080. A autenticação é feita via Authenticator, que intercepta desafios 407 Proxy Authentication Required.
import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
fun createOkHttpProxyClient(): OkHttpClient {
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
return OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator { _, response ->
val credential = okhttp3.Credentials.basic("user-country-DE", "pass")
response.request.newBuilder()
.header("Proxy-Authorization", credential)
.build()
}
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
}
fun main() {
val client = createOkHttpProxyClient()
val request = Request.Builder()
.url("https://httpbin.org/ip")
.build()
client.newCall(request).execute().use { response ->
println(response.body?.string())
// {"origin": "185.xxx.xxx.xxx"} -- IP residencial alemão
}
client.connectionPool.evictAll()
}
Esse padrão é o baseline. O ProxyHat SDK espelha exatamente essa configuração internamente: ele constrói o Proxy, injeta credenciais e gerencia rotação. Se você prefere não lidar com Authenticator manualmente, o SDK abstrai a complexidade.
Roteamento via gate.proxyhat.com: geo-targeting e sessões sticky
A ProxyHat codifica geo-targeting e controle de sessão diretamente no username. Isso significa que você não precisa de endpoints diferentes — basta alterar a string de usuário para mudar país, cidade ou manter um IP fixo.
- País:
user-country-DE - País + cidade:
user-country-DE-city-berlin - Sessão sticky:
user-session-abc123 - Combinado:
user-country-US-session-abc123
Com Ktor Client no engine OkHttp, a configuração do proxy é passada no bloco engine. A autenticação, porém, é engine-specific: o engine CIO não envia credenciais automaticamente, então você precisa adicionar o header Proxy-Authorization em defaultRequest.
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
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
fun createKtorOkHttpProxyClient(
username: String,
password: String
): HttpClient {
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
val credential = Base64.getEncoder()
.encodeToString("$username:$password".toByteArray())
return HttpClient(OkHttp) {
engine {
this.proxy = proxy
}
defaultRequest {
header("Proxy-Authorization", "Basic $credential")
}
}
}
suspend fun main() = coroutineScope {
val client = createKtorOkHttpProxyClient(
username = "user-country-DE-city-berlin",
password = "pass"
)
val response: HttpResponse = client.get("https://httpbin.org/ip")
println(response.bodyAsText())
client.close()
}
Para o engine CIO, que não tem um campo proxy direto, use ProxySelector ou propriedades de sistema. A abordagem mais limpa é definir um ProxySelector global antes de criar o cliente:
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.net.ProxySelector
import java.net.URI
import java.util.Base64
fun createKtorCioProxyClient(
username: String,
password: String
): HttpClient {
val credential = Base64.getEncoder()
.encodeToString("$username:$password".toByteArray())
return HttpClient(CIO) {
defaultRequest {
header("Proxy-Authorization", "Basic $credential")
}
}
}
fun main() = kotlinx.coroutines.runBlocking {
// Define o ProxySelector globalmente
ProxySelector.setDefault(object : ProxySelector() {
override fun select(uri: URI?) = listOf(
Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
)
override fun connectFailed(uri: URI?, sa: InetSocketAddress?, ioe: IOException?) {}
})
val client = createKtorCioProxyClient("user-country-US", "pass")
val response = client.get("https://httpbin.org/ip")
println(response.bodyAsText())
client.close()
}
Dica de produção: Sempre feche o
HttpClientapós o uso. No Android, crie uma única instância noApplicatione reutilize-a — criar um cliente por requisição esgota o pool de conexões rapidamente.
SOCKS5 na porta 1080 com propriedades de sistema
Para tráfego que não é HTTP puro (WebSockets, gRPC, protocolos customizados), o SOCKS5 é mais adequado. A ProxyHat expõe SOCKS5 na porta 1080. No JVM, a forma mais simples é definir propriedades de sistema antes de qualquer requisição:
import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
fun configureSocks5() {
// Autenticação SOCKS5 via propriedades de sistema (JVM)
System.setProperty("socksProxyHost", "gate.proxyhat.com")
System.setProperty("socksProxyPort", "1080")
System.setProperty("java.net.socks.username", "user-country-DE-session-abc123")
System.setProperty("java.net.socks.password", "pass")
}
fun main() {
configureSocks5()
val client = OkHttpClient.Builder()
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("gate.proxyhat.com", 1080)))
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(45, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("https://httpbin.org/ip")
.build()
client.newCall(request).execute().use { response ->
println(response.body?.string())
}
}
Atenção: as propriedades de sistema são globais. Se você precisa de múltiplos proxies SOCKS5 simultâneos, use java.net.Proxy com Authenticator.setDefault() em vez das propriedades:
import java.net.Authenticator
import java.net.InetSocketAddress
import java.net.PasswordAuthentication
import java.net.Proxy
fun createSocks5Proxy(username: String, password: String): Proxy {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(username, password.toCharArray())
}
})
return Proxy(Proxy.Type.SOCKS, InetSocketAddress("gate.proxyhat.com", 1080))
}
Por que proxies residenciais para apps e redes sociais
Alvos como Instagram, TikTok, Amazon e Google mantêm listas detalhadas de ASNs datacenter. Um IP da AWS (54.x.x.x) ou Google Cloud (35.x.x.x) é identificado em milissegundos e recebe um desafio CAPTCHA ou HTTP 429. Proxies residenciais resolvem isso porque o IP pertence a um ISP residencial (Deutsche Telekom, Comcast, Vodafone), passando pela verificação de ASN sem fricção.
Para web scraping em Kotlin com volume significativo, o padrão ideal é fan-out com coroutines: lance múltiplas requisições concorrentes com async/awaitAll, controlando a concorrência com um Semaphore para não exceder o limite do proxy.
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.Base64
suspend fun fetchConcurrent(urls: List<String>): List<String> = coroutineScope {
val semaphore = Semaphore(20) // 20 requisições concorrentes
val client = HttpClient(OkHttp) {
engine {
proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
}
defaultRequest {
val credential = Base64.getEncoder()
.encodeToString("user-country-US:pass".toByteArray())
header("Proxy-Authorization", "Basic $credential")
}
}
val results = urls.map { url ->
async(Dispatchers.IO) {
semaphore.withPermit {
try {
val response = client.get(url)
response.bodyAsText()
} catch (e: Exception) {
println("Erro em $url: ${e.message}")
""
}
}
}
}
val output = results.awaitAll()
client.close()
output
}
fun main() = runBlocking {
val urls = (1..100).map { "https://httpbin.org/ip?req=$it" }
val responses = fetchConcurrent(urls)
responses.forEach { println(it) }
}
Com 20 requisições concorrentes e um Semaphore limitando a concorrência, você evita sobrecarregar o gateway e mantém uma taxa sustentável de aproximadamente 200 requisições por segundo, dependendo da latência do alvo. Se cada requisição leva 100ms, 20 coroutines geram ~200 req/s. Aumente o Semaphore gradualmente e monitore a taxa de sucesso.
Hardening para produção: timeouts, retries e TLS
Em produção, três problemas surgem inevitavelmente: (1) desafios 407 Proxy Authentication Required intermitentes, (2) timeouts em proxies lentos, e (3) certificados TLS que falham em Android. Vamos abordar cada um.
Autenticator para 407 no OkHttp
O Authenticator do OkHttp é chamado automaticamente quando o proxy retorna 407. Implemente-o com lógica de retry limitada para evitar loops infinitos:
import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
class ProxyAuthenticator(
private val username: String,
private val password: String
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
// Evita loop infinito: se já tentamos, desiste
if (response.request.header("Proxy-Authorization") != null) {
return null
}
val credential = Credentials.basic(username, password)
return response.request.newBuilder()
.header("Proxy-Authorization", credential)
.build()
}
}
fun createProductionOkHttp(): OkHttpClient {
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("gate.proxyhat.com", 8080))
return OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(ProxyAuthenticator("user-country-DE", "pass"))
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.connectionPool(ConnectionPool(50, 5, TimeUnit.MINUTES))
.build()
}
Retries com circuit breaker em Kotlin
Para retries com backoff exponencial, combine coroutines com um padrão simples de circuit breaker:
import kotlinx.coroutines.*
import kotlin.math.min
import kotlin.math.pow
suspend fun <T> retryWithBackoff(
maxRetries: Int = 3,
baseDelayMs: Long = 500,
maxDelayMs: Long = 10_000,
block: suspend (attempt: Int) -> T
): T {
var lastException: Exception? = null
repeat(maxRetries) { attempt ->
try {
return block(attempt)
} catch (e: Exception) {
lastException = e
val delay = min(baseDelayMs * 2.0.pow(attempt), maxDelayMs.toDouble()).toLong()
delay(delay)
}
}
throw lastException ?: RuntimeException("Retry exhausted")
}
// Uso:
suspend fun fetchWithRetry(client: HttpClient, url: String): String {
return retryWithBackoff(maxRetries = 3) { attempt ->
val response = client.get(url)
if (response.status.value in 500..599) {
throw RuntimeException("Server error: ${response.status}")
}
response.bodyAsText()
}
}
TLS e Android NetworkSecurityConfig
No Android 9+ (API 28+), o tráfego cleartext é bloqueado por padrão. Se você usa um proxy HTTP na porta 8080, a conexão cliente→proxy é HTTP (não HTTPS), mas a conexão proxy→destino é HTTPS. O Android pode bloquear a conexão com o proxy se o networkSecurityConfig não permitir cleartext para o domínio do gateway. Adicione uma exceção:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">gate.proxyhat.com</domain>
</domain-config>
</network-security-config>
E referencie no AndroidManifest.xml:
<application
android:networkSecurityConfig="@xml/network_security_config"
...>
Para TLS customizado no OkHttp (útil para pinning ou depuração), injete um SSLSocketFactory e X509TrustManager no builder. Em 99% dos casos, o TrustManager padrão é suficiente.
Considerações éticas e legais
Scraping de dados públicos é legal na maioria das jurisdições, mas há limites importantes:
- Estados Unidos: o CFAA (Computer Fraud and Abuse Act) criminaliza acesso não autorizado a sistemas protegidos. O caso Van Buren v. United States (2021) restringiu a interpretação de "exceder acesso autorizado", mas acessar dados protegidos por login ou contornar medidas técnicas de acesso ainda é arriscado.
- União Europeia: o GDPR regula o processamento de dados pessoais. Raspar dados pessoais (nomes, e-mails, IPs) exige base legal (consentimento, interesse legítimo). Dados de empresas e preças públicas geralmente não são dados pessoais.
- Termos de Serviço: muitos sites proíbem scraping nos ToS. Violar ToS pode ser quebra de contrato, mesmo que o scraping em si seja legal.
Antes de raspar, verifique: (1) robots.txt do alvo, (2) se há uma API oficial — frequentemente mais confiável que scraping, (3) se os dados são públicos sem autenticação. Para SERP tracking e price monitoring, consulte os casos de uso de SERP e web scraping da ProxyHat.
Configuração específica da ProxyHat
A ProxyHat oferece proxies residenciais, móveis e datacenter em mais de 150 países. A configuração é sempre a mesma: gateway gate.proxyhat.com, porta 8080 para HTTP e 1080 para SOCKS5, com geo-targeting e sessões no username.
O ProxyHat SDK para Kotlin/JVM encapsula esse padrão. Internamente, ele cria um OkHttpClient ou HttpClient Ktor com o proxy configurado, gerencia rotação de IPs automaticamente e expõe uma API simples:
// Padrão conceitual do ProxyHat SDK (ver docs para API exata)
import com.proxyhat.sdk.ProxyHatClient
val client = ProxyHatClient.builder()
.username("user-country-DE-city-berlin")
.password("pass")
.engine(ProxyHatClient.Engine.OKHTTP)
.maxConcurrent(50)
.build()
val response = client.get("https://httpbin.org/ip")
println(response.body())
Consulte os docs oficiais para a API exata do SDK. O princípio é o mesmo dos exemplos manuais acima — o SDK apenas remove o boilerplate.
Para escolher o plano adequado ao seu volume, veja a página de preços. Proxies residenciais têm custo por GB de tráfego, enquanto datacenter são cobrados por IP ou porta — escolha conforme o tipo de alvo.
Principais takeaways
- OkHttp usa
java.net.Proxy+Authenticatorpara proxy HTTP; Ktor depende do engine e pode exigirProxy-Authorizationmanual emdefaultRequest. - Geo-targeting e sessões sticky são codificados no username:
user-country-DE-city-berlin-session-abc123. - SOCKS5 na porta 1080 usa propriedades de sistema (
socksProxyHost,java.net.socks.username) ouAuthenticator.setDefault(). - Concorrência com coroutines +
Semaphorecontrola a taxa de requisições e evita sobrecarregar o gateway. - Hardening:
Authenticatorpara 407, retries com backoff exponencial, connection pooling eNetworkSecurityConfigno Android. - Ética: respeite
robots.txt, prefira APIs oficiais, e esteja ciente do CFAA e GDPR.
FAQ
O que é usar proxies em Kotlin?
Usar proxies em Kotlin significa configurar clientes HTTP (OkHttp ou Ktor Client) para rotear requisições através de um servidor intermediário (como gate.proxyhat.com:8080), ocultando o IP de origem e permitindo geo-targeting, rotação de IPs e bypass de rate limits. A configuração envolve java.net.Proxy, autenticação via header Proxy-Authorization e, no caso de SOCKS5, propriedades de sistema.
Por que usar proxies em Kotlin importa para usuários de proxy?
Porque Kotlin é a linguagem dominante no Android e amplamente usada em backends JVM. Sem proxy, todo tráfego sai do IP do servidor ou dispositivo, expondo o ASN datacenter e triggerando bloqueios. Proxies residenciais resolvem isso distribuindo o tráfego por IPs de ISPs reais, essencial para scraping, SERP tracking e automação de redes sociais.
Qual tipo de proxy funciona melhor para usar proxies em Kotlin?
Depende do alvo. Para sites que bloqueiam ASNs datacenter (Instagram, Google, Amazon), proxies residenciais são essenciais. Para APIs públicas e alvos sem proteção anti-bot, proxies datacenter são mais rápidos e baratos. Proxies móveis oferecem a maior confiabilidade para alvos agressivos, mas têm custo mais alto. A ProxyHat suporta os três tipos no mesmo gateway.
Como evitar bloqueios ao implementar proxies em Kotlin?
Use rotação de IPs (mude o identificador de sessão a cada requisição ou a cada N requisições), limite a concorrência com Semaphore, adicione delays aleatórios entre requisições, respeite robots.txt, e configure User-Agent realista. Combine com retries com backoff exponencial para lidar com 429 e 503 transitórios. Monitore a taxa de sucesso e ajuste a concorrência conforme necessário.
Ktor Client suporta autenticação proxy automaticamente?
Não em todos os engines. O engine OkHttp herda o Authenticator do OkHttp, mas o engine CIO não envia credenciais automaticamente. Para CIO, adicione o header Proxy-Authorization: Basic ... manualmente em defaultRequest. Sempre teste com httpbin.org/ip para confirmar que o proxy está funcionando antes de ir para produção.






