Usando Proxies em Kotlin: Guia Prático com Ktor e OkHttp

Aprenda a configurar proxies residenciais em Kotlin com Ktor Client e OkHttp, incluindo autenticação, geo-targeting, SOCKS5, concorrência com coroutines e hardening de produção.

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

Se você está construindo clientes HTTP em Kotlin — seja para um backend JVM, um microsserviço ou um app Android — cedo ou tarde esbarra em bloqueios de IP, rate limits e desafios anti-bot. Usando proxies em Kotlin de forma correta significa escolher o tipo de proxy certo, configurar autenticação no nível do engine, gerenciar sessões sticky e lidar com falhas de rede com elegância. Este guia mostra como fazer isso com Ktor Client e OkHttp, dois dos clientes HTTP mais populares do ecossistema Kotlin.

Por que usar proxies em Kotlin com Ktor Client e OkHttp

Proxies resolvem três problemas principais para desenvolvedores Kotlin: (1) contornar bloqueios baseados em IP e ASN, (2) distribuir requisições entre múltiplos IPs para respeitar rate limits, e (3) acessar conteúdo geo-restrito. Quando o alvo é uma API de app ou uma plataforma social, proxies datacenter frequentemente falham porque esses serviços bloqueiam ASNs conhecidos de datacenters. Proxies residenciais, que usam IPs de ISPs reais, têm taxas de sucesso significativamente maiores nesses cenários.

O desafio técnico é que a autenticação de proxy é específica do engine. O Ktor Client não envia automaticamente o header Proxy-Authorization em todos os engines — você precisa configurá-lo manualmente via defaultRequest ou usar o suporte nativo do engine OkHttp. O OkHttp, por outro lado, lida com proxies via java.net.Proxy e oferece um Authenticator dedicado para desafios 407. Entender essas diferenças é metade da batalha.

Para uma visão geral dos padrões de proxy HTTP, consulte a documentação da MDN sobre proxy servers e tunneling. Para o padrão de autenticação Basic, o RFC 7617 define o esquema Basic usado no header Proxy-Authorization.

Configuração do projeto: Ktor 3 e OkHttp

Dependências Gradle (Kotlin DSL)

Para um projeto Kotlin/JVM com Ktor 3.x e OkHttp, adicione as dependências necessárias. O Ktor 3.x usa coroutines e suporta múltiplos engines. O CIO engine é puro Kotlin sem dependências nativas, enquanto o OkHttp engine delega para o OkHttp subjacente.

// build.gradle.kts
dependencies {
    implementation("io.ktor:ktor-client-core:3.0.3")
    implementation("io.ktor:ktor-client-cio:3.0.3")
    implementation("io.ktor:ktor-client-okhttp:3.0.3")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
}

Cliente Ktor com engine CIO

O CIO (Coroutines I/O) é um engine Kotlin puro que não depende de bibliotecas nativas. Ele é leve e funciona bem em qualquer plataforma JVM. Para configurar um proxy HTTP, use o bloco engine e defina o proxy no nível de proxy HTTP do engine.

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.plugins.*
import io.ktor.http.*
import java.util.Base64

fun createKtorClientWithCio(
    proxyHost: String,
    proxyPort: Int,
    username: String,
    password: String
): HttpClient {
    val basicAuth = Base64.getEncoder()
        .encodeToString("$username:$password".toByteArray())

    return HttpClient(CIO) {
        engine {
            proxy = ProxyBuilder.http(Url("http://$proxyHost:$proxyPort"))
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic $basicAuth")
        }
    }
}

// Uso
suspend fun main() {
    val client = createKtorClientWithCio(
        proxyHost = "gate.proxyhat.com",
        proxyPort = 8080,
        username = "user-country-DE-city-berlin",
        password = "sua-senha"
    )
    val resp = client.get("https://httpbin.org/ip")
    println(resp.bodyAsText())
    client.close()
}

Note que o header Proxy-Authorization é adicionado via defaultRequest. Isso é necessário porque o engine CIO não envia credenciais de proxy automaticamente. O engine OkHttp, que veremos a seguir, lida com isso de forma diferente.

Cliente OkHttp com java.net.Proxy

O OkHttp é o cliente HTTP mais usado no Android e em backends Kotlin. A configuração de proxy é direta via OkHttpClient.Builder().proxy(), mas a autenticação exige um Authenticator para responder a desafios 407.

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

fun createOkHttpClient(
    proxyHost: String,
    proxyPort: Int,
    username: String,
    password: String
): OkHttpClient {
    val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxyHost, proxyPort))
    val credential = Credentials.basic(username, password)

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator { _, response ->
            response.request.newBuilder()
                .header("Proxy-Authorization", credential)
                .build()
        }
        .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
        .readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
        .build()
}

// Uso
fun main() {
    val client = createOkHttpClient(
        proxyHost = "gate.proxyhat.com",
        proxyPort = 8080,
        username = "user-country-US-session-abc123",
        password = "sua-senha"
    )
    val request = Request.Builder()
        .url("https://httpbin.org/ip")
        .build()
    client.newCall(request).execute().use { resp ->
        println(resp.body?.string())
    }
}

Aqui o proxyAuthenticator é o caminho idiomático para autenticação proxy OkHttp. Ele intercepta respostas 407 e reenvia a requisição com o header correto. A função Credentials.basic() do OkHttp codifica em Base64 automaticamente.

ProxyHat: roteando pelo gateway com geo-targeting e sessões sticky

O gateway da ProxyHat usa gate.proxyhat.com na porta 8080 para HTTP e 1080 para SOCKS5. A autenticação é via Basic Auth no username, e parâmetros de geo-targeting e sessão são codificados diretamente no username.

ParâmetroFormato no usernameExemplo
Paísuser-country-XXuser-country-DE
Cidadeuser-country-XX-city-nameuser-country-DE-city-berlin
Sessão sticky-session-IDuser-session-abc123
Combinadouser-country-DE-city-berlin-session-abc123Alemanha/Berlim com IP fixo

Veja a lista completa de localizações disponíveis em /pt/locations e detalhes de planos em /pt/pricing.

Exemplo Ktor com geo-targeting e sessão sticky

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.plugins.*
import io.ktor.http.*
import java.util.Base64

fun createGeoProxyClient(country: String, city: String, sessionId: String): HttpClient {
    val username = "user-country-$country-city-$city-session-$sessionId"
    val password = System.getenv("PROXYHAT_PASSWORD") ?: error("Defina PROXYHAT_PASSWORD")
    val basicAuth = Base64.getEncoder()
        .encodeToString("$username:$password".toByteArray())

    return HttpClient(CIO) {
        engine {
            proxy = ProxyBuilder.http(Url("http://gate.proxyhat.com:8080"))
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic $basicAuth")
        }
    }
}

SOCKS5 na porta 1080 via system properties

O SOCKS5 opera na camada de transporte e não usa headers HTTP para autenticação. Em Kotlin/JVM, a forma mais simples é via system properties socksProxyHost, socksProxyPort, java.net.socks.username e java.net.socks.password. O Ktor CIO e o OkHttp respeitam essas propriedades quando nenhum proxy explícito é definido.

import java.net.Authenticator
import java.net.PasswordAuthentication

fun configureSocks5Proxy(username: String, password: String) {
    System.setProperty("socksProxyHost", "gate.proxyhat.com")
    System.setProperty("socksProxyPort", "1080")

    // Autenticação SOCKS5 via java.net.Authenticator
    Authenticator.setDefault(object : Authenticator() {
        override fun getPasswordAuthentication(): PasswordAuthentication {
            return if (requestingScheme.equals("SOCKS5", ignoreCase = true)) {
                PasswordAuthentication(username, password.toCharArray())
            } else {
                null
            }
        }
    })
}

// Exemplo de uso com OkHttp (sem .proxy() — usa system properties)
fun main() {
    configureSocks5Proxy(
        username = "user-country-BR-session-sess1",
        password = System.getenv("PROXYHAT_PASSWORD") ?: ""
    )
    val client = OkHttpClient.Builder().build()
    val req = Request.Builder().url("https://httpbin.org/ip").build()
    client.newCall(req).execute().use { resp ->
        println(resp.body?.string())
    }
}

Atenção: system properties são globais e afetam todas as conexões da JVM. Para isolamento, prefira configurar o proxy explicitamente via java.net.Proxy(Proxy.Type.SOCKS, ...) no OkHttp.

Proxies residenciais para apps e redes sociais

APIs de apps móveis e plataformas sociais como Instagram, TikTok e LinkedIn bloqueiam agressivamente IPs de datacenters. Eles consultam bases de dados ASN como a MaxMind GeoIP2 e rejeitam requisições provenientes de ASNs de hosting (AS14618 da Amazon, AS15169 do Google, etc.). Proxies residenciais usam IPs atribuídos a ISPs reais, tornando o tráfego indistinguível de um usuário doméstico.

Para web scraping Kotlin em escala, o padrão idiomático é fan-out concorrente com coroutines: lançar múltiplas async e aguardar com awaitAll, controlando a concorrência com um Semaphore.

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

suspend fun fetchWithProxy(
    client: HttpClient,
    url: String,
    semaphore: Semaphore
): String = semaphore.withPermit {
    withContext(Dispatchers.IO) {
        try {
            client.get(url).bodyAsText()
        } catch (e: Exception) {
            println("Erro em $url: ${e.message}")
            ""
        }
    }
}

suspend fun main() = coroutineScope {
    val urls = listOf(
        "https://httpbin.org/ip?req=1",
        "https://httpbin.org/ip?req=2",
        "https://httpbin.org/ip?req=3",
        "https://httpbin.org/ip?req=4",
        "https://httpbin.org/ip?req=5"
    )
    val semaphore = Semaphore(3) // máx 3 requisições concorrentes

    val username = "user-country-US"
    val password = System.getenv("PROXYHAT_PASSWORD") ?: error("Defina PROXYHAT_PASSWORD")
    val basicAuth = Base64.getEncoder()
        .encodeToString("$username:$password".toByteArray())

    val client = HttpClient(CIO) {
        engine {
            proxy = ProxyBuilder.http(Url("http://gate.proxyhat.com:8080"))
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic $basicAuth")
        }
    }

    val results = urls.map { url ->
        async { fetchWithProxy(client, url, semaphore) }
    }.awaitAll()

    results.forEachIndexed { i, body ->
        println("Resultado ${i + 1}: ${body.take(100)}")
    }

    client.close()
}

O Semaphore(3) limita a 3 requisições simultâneas, evitando sobrecarregar o proxy ou disparar rate limits do alvo. Cada async roda em Dispatchers.IO, ideal para operações de rede bloqueantes. O awaitAll aguarda todas as coroutines e retorna uma lista de resultados na ordem original.

Para casos de uso mais detalhados, veja /pt/use-cases/web-scraping e /pt/use-cases/serp-tracking.

Hardening de produção

OkHttp: Authenticator para 407, retries e timeouts

Em produção, conexões proxy caem, proxies retornam 407 intermitentemente e o servidor alvo pode responder lentamente. O OkHttp oferece ferramentas nativas para lidar com tudo isso.

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

fun createProductionClient(
    proxyHost: String,
    proxyPort: Int,
    username: String,
    password: String
): OkHttpClient {
    val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxyHost, proxyPort))
    val credential = Credentials.basic(username, password)

    return OkHttpClient.Builder()
        .proxy(proxy)
        .proxyAuthenticator { _, response ->
            // Responde a 407 reenviando com credencial
            response.request.newBuilder()
                .header("Proxy-Authorization", credential)
                .build()
        }
        .connectTimeout(15, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .connectionPool(ConnectionPool(50, 5, TimeUnit.MINUTES))
        .build()
}

O ConnectionPool(50, 5, TimeUnit.MINUTES) mantém até 50 conexões keep-alive por 5 minutos, reduzindo overhead de handshake TLS. retryOnConnectionFailure(true) permite ao OkHttp tentar reconectar automaticamente em falhas transitórias.

Ktor: timeouts e logging

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.plugins.observer.*
import io.ktor.http.*
import java.util.Base64
import kotlin.time.Duration.Companion.seconds

fun createKtorProductionClient(username: String, password: String): HttpClient {
    val basicAuth = Base64.getEncoder()
        .encodeToString("$username:$password".toByteArray())

    return HttpClient(CIO) {
        engine {
            proxy = ProxyBuilder.http(Url("http://gate.proxyhat.com:8080"))
            requestTimeout = 30.seconds.inWholeMilliseconds
        }
        install(HttpTimeout) {
            connectTimeoutMillis = 15_000
            requestTimeoutMillis = 30_000
            socketTimeoutMillis = 30_000
        }
        install(Logging) {
            level = LogLevel.HEADERS
            logger = Logger.SIMPLE
        }
        defaultRequest {
            header("Proxy-Authorization", "Basic $basicAuth")
            header("User-Agent", "MyApp/1.0")
        }
    }
}

Notas sobre Android NetworkSecurityConfig

No Android 9+ (API 28+), tráfego em texto plano é bloqueado por padrão. Se o proxy usa HTTP (não HTTPS) para o CONNECT tunnel, adicione uma network_security_config.xml permitindo o domínio do gateway. Na prática, o ProxyHat usa HTTP CONNECT para tunelar HTTPS, então o tráfego final permanece criptografado end-to-end. Mesmo assim, configure a exception para o host do proxy:

<!-- 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"
    ...>

SDK da ProxyHat

O SDK da ProxyHat espelha esse padrão: você fornece as credenciais e o SDK constrói o header Proxy-Authorization e gerencia o pool de conexões internamente. Para detalhes de integração, consulte a documentação oficial da ProxyHat.

Considerações éticas e legais

Scraping é uma área legalmente sensível. Nos EUA, o Computer Fraud and Abuse Act (CFAA) criminaliza acesso não autorizado a sistemas computacionais, embão decisões recentes (como hiQ Labs v. LinkedIn) tenham limitado sua aplicação a dados públicos. Na UE, o GDPR regula o processamento de dados pessoais — raspar dados pessoais sem base legal pode resultar em multas de até €20 milhões ou 4% do faturamento global.

Boas práticas:

  • Respeite robots.txt e os Termos de Serviço do alvo.
  • Use rate limits razoáveis — 1-2 requisições por segundo por IP é um bom começo.
  • Prefira APIs oficiais quando disponíveis. Muitas plataformas oferecem APIs gratuitas ou de baixo custo.
  • Colete apenas dados públicos e necessários para seu caso de uso.
  • Considere o impacto no servidor alvo — monitore latência e backoff.

Erros comuns e edge cases

  • Esquecer o header Proxy-Authorization no CIO engine: o CIO não envia credenciais automaticamente. Sem o header, você recebe 407 repetidamente.
  • Misturar system properties SOCKS5 com proxy HTTP explícito: se ambos estiverem configurados, o comportamento é indefinido. Escolha um approach.
  • Não tratar 407 como retryable: proxies residenciais podem retornar 407 intermitentemente se o IP subjacente cair. Implemente retry com backoff exponencial.
  • Usar o mesmo session ID para todas as requisições: isso fixa o IP, o que é útil para login flows mas reduz o paralelismo efetivo. Use session IDs diferentes para fan-out.
  • Ignorar o User-Agent: muitos alvos bloqueiam User-Agens padrão de bibliotecas HTTP. Defina um UA realista via defaultRequest.

Principais takeaways

Resumo dos pontos-chave:

  • No Ktor CIO, adicione Proxy-Authorization via defaultRequest — o engine não envia automaticamente.
  • No OkHttp, use proxyAuthenticator para responder a desafios 407 de forma idiomática.
  • Para SOCKS5 na porta 1080, use system properties ou java.net.Proxy(Proxy.Type.SOCKS, ...).
  • Proxies residenciais são essenciais para apps e redes sociais que bloqueiam ASNs de datacenter.
  • Controle concorrência com Semaphore e async/awaitAll para respeitar rate limits.
  • Em produção, configure timeouts, connection pooling e retry com backoff exponencial.
  • Respeite robots.txt, ToS e legislação aplicável (CFAA, GDPR).

FAQ

O que é usar proxies em Kotlin?

É a configuração de clientes HTTP Kotlin — como Ktor Client e OkHttp — para rotear requisições através de um servidor proxy intermediário. Isso envolve definir o endereço do proxy, configurar autenticação (geralmente Basic Auth via header Proxy-Authorization), e opcionalmente geo-targeting e sessões sticky. O objetivo é contornar bloqueios de IP, distribuir carga e acessar conteúdo geo-restrito.

Por que usar proxies em Kotlin importa para desenvolvedores?

Porque a autenticação de proxy é específica do engine. O Ktor CIO não envia Proxy-Authorization automaticamente, exigindo configuração manual via defaultRequest. O OkHttp usa um Authenticator dedicado para desafios 407. Ignorar essas diferenças resulta em erros 407, timeouts e falhas silenciosas. Entender o mecanismo de cada cliente é essencial para integrações robustas.

Qual tipo de proxy funciona melhor para uso em Kotlin?

Depende do alvo. Para APIs web genéricas, proxies datacenter são rápidos e baratos. Para apps móveis, redes sociais e sites com proteção anti-bot, proxies residenciais são necessários porque esses serviços bloqueiam ASNs de datacenter. Proxies móveis oferecem a maior credibilidade mas são mais caros. A ProxyHat oferece os três tipos — escolha com base no caso de uso e orçamento.

Como evitar bloqueios ao usar proxies em Kotlin?

Use proxies residenciais com rotação de IPs, respeite rate limits (1-2 req/s por IP é um bom começo), implemente retry com backoff exponencial para 407 e 429, defina User-Agents realistas, use sessões sticky apenas quando necessário (login flows) e monitore a taxa de sucesso. Controle concorrência com Semaphore e distribua requisições entre múltiplos session IDs.

Como configurar SOCKS5 com ProxyHat em Kotlin?

Use a porta 1080 do gateway gate.proxyhat.com. Em Kotlin/JVM, defina as system properties socksProxyHost e socksProxyPort, e use java.net.Authenticator para fornecer username e password. Alternativamente, configure java.net.Proxy(Proxy.Type.SOCKS, InetSocketAddress(...)) explicitamente no OkHttp para isolamento. O formato do username suporta geo-targeting e sessões, igual ao HTTP.

Perguntas frequentes

O que é usar proxies em Kotlin?

É a configuração de clientes HTTP Kotlin — como Ktor Client e OkHttp — para rotear requisições através de um servidor proxy intermediário. Isso envolve definir o endereço do proxy, configurar autenticação (geralmente Basic Auth via header Proxy-Authorization), e opcionalmente geo-targeting e sessões sticky. O objetivo é contornar bloqueios de IP, distribuir carga e acessar conteúdo geo-restrito.

Por que usar proxies em Kotlin importa para desenvolvedores?

Porque a autenticação de proxy é específica do engine. O Ktor CIO não envia Proxy-Authorization automaticamente, exigindo configuração manual via defaultRequest. O OkHttp usa um Authenticator dedicado para desafios 407. Ignorar essas diferenças resulta em erros 407, timeouts e falhas silenciosas. Entender o mecanismo de cada cliente é essencial para integrações robustas.

Qual tipo de proxy funciona melhor para uso em Kotlin?

Depende do alvo. Para APIs web genéricas, proxies datacenter são rápidos e baratos. Para apps móveis, redes sociais e sites com proteção anti-bot, proxies residenciais são necessários porque esses serviços bloqueiam ASNs de datacenter. Proxies móveis oferecem a maior credibilidade mas são mais caros. A ProxyHat oferece os três tipos — escolha com base no caso de uso e orçamento.

Como evitar bloqueios ao usar proxies em Kotlin?

Use proxies residenciais com rotação de IPs, respeite rate limits (1-2 req/s por IP é um bom começo), implemente retry com backoff exponencial para 407 e 429, defina User-Agents realistas, use sessões sticky apenas quando necessário (login flows) e monitore a taxa de sucesso. Controle concorrência com Semaphore e distribua requisições entre múltiplos session IDs.

Como configurar SOCKS5 com ProxyHat em Kotlin?

Use a porta 1080 do gateway gate.proxyhat.com. Em Kotlin/JVM, defina as system properties socksProxyHost e socksProxyPort, e use java.net.Authenticator para fornecer username e password. Alternativamente, configure java.net.Proxy(Proxy.Type.SOCKS, InetSocketAddress(...)) explicitamente no OkHttp para isolamento. O formato do username suporta geo-targeting e sessões, igual ao HTTP.

Pronto para começar?

Proxies residenciais, ISP e móveis em mais de 148 países. Crie uma conta grátis.

Criar conta grátis
← Voltar ao Blog