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-targetinguser-country-US-city-newyork— şehir düzeyinde geo-targetinguser-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.
NSAllowsArbitraryLoads'ıtrueyapmak 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.txtdosyası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:
- Fiyatlandırma sayfası — residential, mobile ve datacenter planları
- Proxy lokasyonları — 100+ ülke ve şehir düzeyinde geo-targeting
- Web scraping kullanım senaryosu
- SERP takip kullanım senaryosu
Önemli Noktalar
connectionProxyDictionaryile HTTP ve HTTPS proxy'yigate.proxyhat.com:8080üzerinden yönlendirin.kCFProxyUsername/PasswordKeygüvenilir değil;Proxy-Authorization: Basicheader veya delegate ile 407 challenge kullanın.- SOCKS5 için
kCFStreamPropertySOCKSProxy*anahtarları ve port1080kullanın. - Geo-targeting için kullanıcı adında
country-US-city-newyork-session-abc123formatı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.






