Swift'de Proxy Kullanımı: URLSession ile HTTP/SOCKS5 Yapılandırması

Swift'de proxy kullanımı için URLSession proxy yapılandırması, HTTP/SOCKS5 ayarları, kimlik doğrulama, geo-targeting ve async/await desenleri. Kod örnekleriyle adım adım production rehberi.

Using Proxies in Swift: A Code-First URLSession Guide for iOS & macOS

iOS veya macOS uygulamanızdan bir API'ye istek attınız ve "403 Forbidden" aldınız. Veya bölgesel kısıtlamalı içeriğe erişmeye çalıştığınızda "Bu içerik bölgenizde kullanılamıyor" mesajıyla karşılaştınız. Bu tür sorunlar, Swift'de proxy kullanımı konusunu gündeme getirir. URLSession, proxy yapılandırması için güçlü ama belgeleri sınırlı olan bir API sunar.

Bu rehberde, Swift proxy yapılandırmasını sıfırdan production'a kadar adım adım inceleyeceğiz: URLSessionConfiguration.connectionProxyDictionary ayarları, kimlik doğrulama, SOCKS5, async/await desenleri ve daha fazlası. Hedef kittemiz iOS ve macOS geliştiricileri olduğundan, tüm örnekler URLSession üzerine kurulu olacak.

Swift'de Proxy Kullanımı: Neden Gerekli?

Birçok web servisi ve API, gelen isteklerin IP adresini kontrol eder. Datacenter IP'leri genellikle blok listelerdedir çünkü otomatik trafikle ilişkilendirilirler. URLSession proxy yapılandırması, isteklerinizi farklı bir IP'den göndermenizi sağlar ve IP tabanlı engellemeleri aşmanıza olanak tanır.

Residential proxy'ler, gerçek ISP'lere ait IP adresleri kullandığı için normal kullanıcı trafiğine benzeyen istekler gönderir. Bu, Swift web scraping veya bölgesel içerik erişimi için kritik bir avantajdır. Datacenter IP'leri ise Cloudflare ve benzeri WAF sağlayıcıları tarafından genellikle engellenir.

Proxy Türleri Karşılaştırması

Özellik Residential Datacenter Mobile
Ortalama Gecikme ~200ms ~50ms ~400ms
Tespit Edilme Riski Düşük Yüksek Çok Düşük
Fiyat (GB başına) Orta-Yüksek Düşük Yüksek
Uygun Kullanım Web scraping, API erişimi Hızlı istekler, test Sosyal medya, mobil uygulama taklit

Residential proxy'ler, datacenter IP'lerinin engellendiği uç noktalara erişim için en iyi seçenektir. ProxyHat, 100+ ülkede residential proxy sunar ve esnek fiyatlandırma seçenekleri sağlar.

HTTP Proxy Yapılandırması: connectionProxyDictionary

URLSession'da proxy yapılandırmanın temel yolu, URLSessionConfiguration.connectionProxyDictionary özelliğini ayarlamaktır. Bu sözlük, CFNetwork framework'ünün proxy anahtarlarını kullanır. Apple'ın URLSessionConfiguration belgelerine göre, bu özellik hem HTTP hem de HTTPS trafiğini yönlendirebilir.

Aşağıdaki örnekte, hem HTTP hem de HTTPS trafiğini ProxyHat gateway'ine yönlendiriyoruz:

import Foundation

let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable: true,
    kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPPort: 8080,
    kCFNetworkProxiesHTTPSEnable: true,
    kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPSPort: 8080
]

let session = URLSession(configuration: config)
let url = URL(string: "https://api.example.com/data")!
let task = session.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Hata: \(error)")
        return
    }
    if let data = data, let body = String(data: data, encoding: .utf8) {
        print("Yanıt: \(body)")
    }
}
task.resume()

Bu yapılandırma tüm HTTP ve HTTPS isteklerini gate.proxyhat.com:8080 üzerinden yönlendirir. Ancak kimlik doğrulama eksik olduğu için proxy 407 Proxy Authentication Required yanıtı döndürür. Kimlik doğrulamayı sonraki bölümde ele alacağız.

Kimlik Doğrulama ve Geo-Targeting

kCFProxyUsername ve kCFProxyPasswordKey anahtarları URLSession'de güvenilir çalışmaz — bazı iOS sürümlerinde kimlik bilgileri proxy'ye iletilmez. Bunun yerine iki yaklaşım önerilir:

Yaklaşım 1: Proxy-Authorization Header

En basit ve en güvenilir yöntem, her isteğe Proxy-Authorization: Basic header'ı eklemektir. ProxyHat kullanıcı adında geo-targeting ve session parametreleri taşıyabilirsiniz. Kullanıcı adı formatı user-country-US-city-newyork-session-abc123 şeklindedir:

import Foundation

let username = "user-country-US-city-newyork-session-abc123"
let password = "your_password"
let credentials = "\(username):\(password)"
let encoded = Data(credentials.utf8).base64EncodedString()

var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
request.setValue("Basic \(encoded)", forHTTPHeaderField: "Proxy-Authorization")

let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable: true,
    kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPPort: 8080,
    kCFNetworkProxiesHTTPSEnable: true,
    kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPSPort: 8080
]

let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Hata: \(error)")
        return
    }
    if let http = response as? HTTPURLResponse {
        print("Durum kodu: \(http.statusCode)")
    }
}
task.resume()

Yaklaşım 2: URLSessionDelegate ile 407 Challenge

Proxy 407 yanıtı gönderdiğinde, URLSession bir URLAuthenticationChallenge tetikler. urlSession(_:didReceive:completionHandler:) metodunu uygulayarak kimlik bilgilerini sağlayabilirsiniz. Bu yöntem, header eklemeyi unutma riskini ortadan kaldırır:

class ProxyAuthDelegate: NSObject, URLSessionDelegate {
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        let space = challenge.protectionSpace
        guard space.authenticationMethod == NSURLAuthenticationMethodHTTPProxy ||
              space.authenticationMethod == NSURLAuthenticationMethodHTTPSProxy else {
            completionHandler(.performDefaultHandling, nil)
            return
        }
        let credential = URLCredential(
            user: "user-country-US-city-newyork-session-abc123",
            password: "your_password",
            persistence: .forSession
        )
        completionHandler(.useCredential, credential)
    }
}

let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable: true,
    kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPPort: 8080,
    kCFNetworkProxiesHTTPSEnable: true,
    kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPSPort: 8080
]

let delegate = ProxyAuthDelegate()
let session = URLSession(configuration: config, delegate: delegate, delegateQueue: nil)

ProxyHat kullanıcı adı formatı şu parametreleri destekler:

  • user-country-US — ülke düzeyinde geo-targeting
  • user-country-US-city-newyork — şehir düzeyinde geo-targeting
  • user-session-abc123 — sticky session (aynı IP'yi korur)
  • user-country-DE-city-berlin-session-xyz789 — kombine kullanım

Sticky session kullanmadığınızda, ProxyHat her isteği farklı bir residential IP'den yönlendirir. Bu, IP rotasyonu için ek kod yazmanızı gerektirmez.

SOCKS5 Proxy Yapılandırması

Bazı durumlarda HTTP proxy yerine SOCKS5 kullanmak isteyebilirsiniz. SOCKS5, TCP düzeyinde çalıştığı için daha düşük overhead sunar ve tüm protokolleri destekler. ProxyHat, SOCKS5 için gate.proxyhat.com:1080 uç noktası sunar. kCFStreamPropertySOCKSProxy* anahtarlarını kullanarak yapılandırabilirsiniz:

import Foundation

let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
    kCFStreamPropertySOCKSProxyHost: "gate.proxyhat.com",
    kCFStreamPropertySOCKSProxyPort: 1080,
    kCFStreamPropertySOCKSVersion: kCFStreamSocketSOCKSVersion5,
    kCFStreamPropertySOCKSUser: "user-country-US-session-abc123",
    kCFStreamPropertySOCKSPassword: "your_password"
]

let session = URLSession(configuration: config)
let url = URL(string: "https://api.example.com/data")!
let task = session.dataTask(with: url) { data, response, error in
    if let error = error {
        print("SOCKS5 hata: \(error)")
        return
    }
    print("SOCKS5 başarı: \(response)")
}
task.resume()

SOCKS5 kimlik doğrulaması bazı URLSession sürümlerinde güvenilir olmayabilir. Bu durumda, yukarıda gösterilen Proxy-Authorization header yaklaşımını kullanın. HTTP proxy (port 8080) çoğu senaryo için yeterlidir; SOCKS5'i yalnızca özel ağ gereksinimleriniz varsa tercih edin.

Async/Await ile Eşzamanlı İstekler

Modern Swift'te async/await ve TaskGroup kullanarak eşzamanlı istekler gönderebilirsiniz. Bu desen, iOS proxy URLSession kullanımı için idealdir. Aşağıdaki örnek, birden fazla ürünü eşzamanlı olarak çeker ve her istek için farklı bir residential IP kullanır:

import Foundation

struct Product: Codable {
    let id: Int
    let name: String
    let price: Double
}

func fetchProducts(ids: [Int]) async throws -> [Product] {
    let config = URLSessionConfiguration.default
    config.connectionProxyDictionary = [
        kCFNetworkProxiesHTTPEnable: true,
        kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
        kCFNetworkProxiesHTTPPort: 8080,
        kCFNetworkProxiesHTTPSEnable: true,
        kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
        kCFNetworkProxiesHTTPSPort: 8080
    ]

    let username = "user-country-US-session-\(UUID().uuidString.prefix(8))"
    let password = "your_password"
    let encoded = Data("\(username):\(password)".utf8).base64EncodedString()

    let delegate = TLSRetryDelegate()
    let session = URLSession(configuration: config, delegate: delegate, delegateQueue: nil)

    return try await withThrowingTaskGroup(of: Product.self) { group in
        for id in ids {
            group.addTask {
                var request = URLRequest(
                    url: URL(string: "https://api.example.com/products/\(id)")!
                )
                request.setValue("Basic \(encoded)", forHTTPHeaderField: "Proxy-Authorization")
                let (data, response) = try await session.data(for: request)
                guard let http = response as? HTTPURLResponse,
                      http.statusCode == 200 else {
                    throw URLError(.badServerResponse)
                }
                return try JSONDecoder().decode(Product.self, from: data)
            }
        }
        var products: [Product] = []
        for try await product in group {
            products.append(product)
        }
        return products
    }
}

// Kullanım
Task {
    do {
        let products = try await fetchProducts(ids: [1, 2, 3, 4, 5])
        for product in products {
            print("\(product.name): $\(product.price)")
        }
    } catch {
        print("Toplu istek hatası: \(error)")
    }
}

Bu örnekte her istek için benzersiz bir session ID kullanılır (UUID().uuidString.prefix(8)), böylece her istek farklı bir residential IP'den gelir. TaskGroup ile 5 veya daha fazla isteği eşzamanlı olarak gönderebilirsiniz. ProxyHat, 100+ eşzamanlı oturumu destekler.

Production İpuçları

TLS/SSL Yönetimi

Bazı proxy kurulumlarında sertifika doğrulama sorunları yaşanabilir. Aşağıdaki delegate, TLS challenge'larını güvenli şekilde ele alır ve proxy üzerinden gelen sertifikaları kabul eder:

class TLSRetryDelegate: NSObject, URLSessionDelegate {
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if let trust = challenge.protectionSpace.serverTrust {
                completionHandler(.useCredential, URLCredential(trust: trust))
            } else {
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        } else {
            completionHandler(.performDefaultHandling, nil)
        }
    }
}

Güvenlik notu: Production'da sertifika doğrulamayı asla tamamen kapatmayın. Yukarıdaki kod, proxy'nin TLS'sini güvenli şekilde kabul eder ama sunucu sertifikalarını doğrulamayı bırakmaz. NSAllowsArbitraryLoadstrue yapmak yerine, yalnızca gerekli domain'ler için ATS istisnası tanımlayın.

Üstel Geri Çekilme (Exponential Backoff) ile Yeniden Deneme

429 Too Many Requests veya 503 Service Unavailable yanıtlarında, üstel geri çekilme stratejisi kullanın. Aşağıdaki fonksiyon, 3 deneme yapar ve her deneme arasında 2x gecikme uygular:

func fetchWithRetry(
    url: URL,
    maxRetries: Int = 3,
    baseDelay: TimeInterval = 1.0
) async throws -> Data {
    var attempt = 0
    while true {
        do {
            var request = URLRequest(url: url)
            let encoded = Data("user-country-US:your_password".utf8).base64EncodedString()
            request.setValue("Basic \(encoded)", forHTTPHeaderField: "Proxy-Authorization")
            let (data, response) = try await URLSession.shared.data(for: request)
            if let http = response as? HTTPURLResponse,
               http.statusCode == 429 || http.statusCode == 503 {
                throw URLError(.resourceUnavailable)
            }
            guard let http = response as? HTTPURLResponse,
                  (200...299).contains(http.statusCode) else {
                throw URLError(.badServerResponse)
            }
            return data
        } catch {
            attempt += 1
            if attempt >= maxRetries { throw error }
            let delay = baseDelay * pow(2.0, Double(attempt - 1))
            try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
        }
    }
}

Bu desen, 1 saniye, 2 saniye, 4 saniye aralıklarla yeniden deneme yapar. Rate limit'e takılma olasılığını büyük ölçüde azaltır.

App Transport Security (ATS)

Apple, App Transport Security (ATS) ile tüm ağ trafiğinin TLS 1.2+ kullanmasını zorunlu kılar. Proxy kullanırken ATS kuralları hedef sunucu için geçerlidir; proxy sunucusu için değildir. Eğer hedef sunucu HTTPS kullanıyorsa ek bir ATS yapılandırması gerekmez.

HTTP hedef sunuculara erişim için Info.plist dosyasında ATS istisnaları tanımlamanız gerekir:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>api.example.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

Cihaz Bazlı Gizlilik Notları

iOS'ta proxy kullanırken kullanıcı gizliliğini dikkate alın:

  • Kullanıcı şeffaflığı: Uygulamanızın proxy kullandığını kullanım koşullarında ve gizlilik politikasında belirtin.
  • Kimlik bilgilerini Keychain'de saklayın, hardcoded string olarak değil.
  • Proxy trafiğini App Store incelemesi için dokümante edin; Apple, ağ kullanımını şeffaf olmasını bekler.
  • Kullanıcı verilerini proxy üzerinden göndermekten kaçının; yalnızca herkese açık verilere erişin.

Etik ve Yasal Hususlar

Swift web scraping ve proxy kullanımı güçlü araçlardır ama yasal sınırlar içinde kullanılmalıdır:

  • ABD'de CFAA: Computer Fraud and Abuse Act, yetkisiz bilgisayar erişimini yasaklar. Herkese açık verilere erişim genellikle kabul edilebilir, ancak hedef servisin kullanım şartlarını (ToS) ihlal etmek risk oluşturabilir.
  • AB'de GDPR: Kişisel verilerin işlenmesi açık rıza gerektirir. GDPR kapsamında kişisel veri içeren scraping dikkatli değerlendirilmelidir. Yalnızca herkese açık, kişisel olmayan veriler için proxy kullanın.
  • App Store Kuralları: Apple'ın App Store Review Guidelines'ı, uygulamaların kullanıcı verilerini şeffaf şekilde işlemesini ve izinsiz veri toplamamasını gerektirir.
  • Resmi API'ler: Her zaman önce resmi API'leri kontrol edin. Birçok servis, scraping'e gerek kalmadan veri erişimi sunar. Resmi API varsa, proxy kullanmadan doğrudan API'yi kullanın.

Önemli: Bu rehber yalnızca herkese açık verilere meşru erişim içindir. Her zaman hedef servisin robots.txt dosyasını ve kullanım şartlarını kontrol edin. Web scraping kullanım senaryosu sayfamızda etik scraping hakkında daha fazla bilgi bulabilirsiniz.

ProxyHat ile Entegrasyon

ProxyHat, gate.proxyhat.com gateway'i üzerinden residential, mobile ve datacenter proxy hizmetleri sunar. Yukarıdaki tüm kod örnekleri bu gateway'i kullanır. HTTP için port 8080, SOCKS5 için port 1080 kullanın.

ProxyHat ayrıca Python ve Node.js SDK'ları sunar. Bu SDK'lar aynı gate.proxyhat.com gateway'ini kullanır, böylece backend tarafında Swift uygulamanızla aynı proxy altyapısını kullanabilirsiniz. Swift için resmi bir SDK bulunmaz; bu rehberde gösterilen raw URLSession yaklaşımı, Swift'te proxy kullanmanın standart yöntemidir.

Daha fazla bilgi için:

Önemli Noktalar

  • connectionProxyDictionary ile HTTP ve HTTPS proxy'yi gate.proxyhat.com:8080 üzerinden yönlendirin.
  • kCFProxyUsername/PasswordKey güvenilir değil; Proxy-Authorization: Basic header veya delegate ile 407 challenge kullanın.
  • SOCKS5 için kCFStreamPropertySOCKSProxy* anahtarları ve port 1080 kullanın.
  • Geo-targeting için kullanıcı adında country-US-city-newyork-session-abc123 formatını kullanın.
  • Async/await ve TaskGroup ile eşzamanlı istekler gönderin; her istek için yeni session ID kullanın.
  • Üstel geri çekilme ile 429/503 hatalarını yönetin; 3 deneme ve 2x gecikme iyi bir başlangıçtır.
  • ATS kuralları hedef sunucu için geçerlidir; HTTPS hedefler için ek yapılandırma gerekmez.
  • Herkese açık verilere meşru erişim için proxy kullanın; ToS, GDPR ve App Store kurallarına uyun.

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