Wenn Sie Proxies in Swift verwenden möchten, stehen Sie vor einer besonderen Herausforderung: Die URLSession-API von Apple bietet keine eingebaute Proxy-Verwaltung wie Python oder Node.js. Stattdessen müssen Sie URLSessionConfiguration.connectionProxyDictionary manuell konfigurieren und Authentifizierungs-Header selbst setzen. Dieser Guide zeigt Ihnen, wie Sie HTTP- und SOCKS5-Proxys in iOS- und macOS-Apps integrieren — mit runnable Code-Beispielen, Geo-Targeting, async/await und Produktionstipps für Swift Web Scraping.
Proxies in Swift verwenden: Grundlagen und URLSession
Ein Swift Proxy leitet HTTP- oder SOCKS5-Traffic über einen Zwischenserver, bevor er das Ziel erreicht. Auf iOS und macOS erfolgt dies über URLSession, Apples primäres Networking-Framework. Die Konfiguration läuft über URLSessionConfiguration, das ein connectionProxyDictionary akzeptiert — ein Dictionary mit CFNetwork-Konstanten als Schlüsseln.
Die Herausforderung: Apple unterstützt keine direkte Proxy-Authentifizierung über kCFProxyUsernameKey und kCFProxyPasswordKey in URLSession. Diese Schlüssel werden auf Plattformen wie macOS teilweise ignoriert. Die zuverlässige Lösung ist ein Proxy-Authorization-Header oder die Implementierung des urlSession(_:didReceive:completionHandler:)-Delegaten für 407-Herausforderungen.
Residential Proxys sind besonders wichtig, wenn App-Endpunkte Datacenter-IPs blockieren oder inhaltsabhängige Geo-Beschränkungen durchsetzen. Ein URLSession Proxy mit residentialen IPs tarnt Ihre Anfragen als reguläre Endbenutzer-Verbindungen und umgeht einfache IP-basierte Sperren. Weitere Hintergrundinformationen finden Sie in der offiziellen URLSession-Dokumentation von Apple.
HTTP-Proxy mit URLSessionConfiguration konfigurieren
Der erste Schritt ist die Konfiguration eines HTTP/HTTPS-Proxys über connectionProxyDictionary. Sie setzen kCFNetworkProxiesHTTPEnable auf true und geben Host sowie Port an. Für HTTPS-Verbindungen verwenden Sie die kCFNetworkProxiesHTTPSEnable-Familie. Der Standard-Port für ProxyHat HTTP ist 8080.
Grundlegende Proxy-Konfiguration
import Foundation
func createProxySession() -> URLSession {
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPPort: 8080,
kCFNetworkProxiesHTTPSEnable: true,
kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPSPort: 8080
]
return URLSession(configuration: config)
}
// Basis-Nutzung ohne Authentifizierung
let session = createProxySession()
let url = URL(string: "https://httpbin.org/ip")!
let task = session.dataTask(with: url) { data, response, error in
if let data = data {
print(String(data: data, encoding: .utf8) ?? "Keine Daten")
}
}
task.resume()
Authentifizierung und Geo-Targeting
Da kCFProxyUsernameKey und kCFProxyPasswordKey in URLSession unzuverlässig sind, gibt es zwei Ansätze: einen Proxy-Authorization: Basic-Header manuell setzen oder den URLSessionDelegate für 407-Challenges implementieren. Bei ProxyHat kodieren Sie Geo-Targeting und Session-IDs direkt im Benutzernamen — z. B. user-country-US-city-newyork-session-abc123.
Ansatz 1: Proxy-Authorization-Header
import Foundation
func makeProxiedRequest(targetURL: URL) async throws -> Data {
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPPort: 8080,
kCFNetworkProxiesHTTPSEnable: true,
kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPSPort: 8080
]
// Benutzername mit Geo-Targeting und Session-ID
let username = "user-country-US-city-newyork-session-abc123"
let password = "pass"
let token = "\(username):\(password)"
let encoded = Data(token.utf8).base64EncodedString()
var request = URLRequest(url: targetURL)
request.setValue("Basic \(encoded)", forHTTPHeaderField: "Proxy-Authorization")
let session = URLSession(configuration: config)
let (data, response) = try await session.data(for: request)
guard let httpResp = response as? HTTPURLResponse,
(200...299).contains(httpResp.statusCode) else {
throw URLError(.badServerResponse)
}
return data
}
Ansatz 2: URLSessionDelegate für 407-Challenge
import Foundation
final class ProxyAuthDelegate: NSObject, URLSessionDelegate {
let username: String
let password: String
init(username: String, password: String) {
self.username = username
self.password = password
}
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodHTTPProxy,
NSURLAuthenticationMethodHTTPSProxy:
let cred = URLCredential(
user: username,
password: password,
persistence: .forSession
)
completionHandler(.useCredential, cred)
default:
completionHandler(.performDefaultHandling, nil)
}
}
}
// Nutzung mit Geo-Targeting im Benutzernamen
let delegate = ProxyAuthDelegate(
username: "user-country-DE-city-berlin-session-xyz789",
password: "pass"
)
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, delegate: delegate, delegateQueue: nil)
SOCKS5-Proxy in Swift verwenden
Für SOCKS5-Verbindungen über Port 1080 verwenden Sie die kCFStreamPropertySOCKSProxy*-Schlüssel. SOCKS5 ist nützlich, wenn Sie TCP-Traffic jenseits von HTTP/HTTPS tunneln müssen oder wenn bestimmte Endpunkte HTTP-Proxys blockieren. Der ProxyHat-SOCKS5-Gateway läuft auf derselben Adresse gate.proxyhat.com, nur auf einem anderen Port.
import Foundation
func createSOCKS5Session() -> URLSession {
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFStreamPropertySOCKSProxyHostKey: "gate.proxyhat.com",
kCFStreamPropertySOCKSProxyPortKey: 1080,
kCFStreamPropertySOCKSProxyVersionKey: kCFStreamSocketSOCKSVersion5
]
// Auch hier: Proxy-Authorization-Header oder Delegate verwenden
return URLSession(configuration: config)
}
Async/Await mit Proxys: Web Scraping in Swift
Swift Web Scraping mit async/await und Proxys ist mit URLSession.shared.data(for:) unkompliziert. Für parallele Anfragen an mehrere Endpunkte verwenden Sie eine TaskGroup. Das folgende Beispiel zeigt eine iOS Proxy URLSession-Implementierung, die JSON-Daten von mehreren URLs concurrently abruft und mit Codable dekodiert. Mit residentialen Proxys liegt die typische End-to-End-Latenz bei 200–500ms pro Request.
import Foundation
struct PriceResult: Decodable {
let product: String
let price: Double
let currency: String
}
func makeProxiedSession(country: String, city: String, sessionID: String) -> URLSession {
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPPort: 8080,
kCFNetworkProxiesHTTPSEnable: true,
kCFNetworkProxiesHTTPSProxy: "gate.proxyhat.com",
kCFNetworkProxiesHTTPSPort: 8080
]
config.timeoutIntervalForRequest = 30
config.timeoutIntervalForResource = 60
return URLSession(configuration: config)
}
func fetchPrices(urls: [URL], country: String) async throws -> [PriceResult] {
let session = makeProxiedSession(
country: country,
city: "berlin",
sessionID: "batch-\(UUID().uuidString.prefix(8))"
)
return try await withThrowingTaskGroup(of: PriceResult?.self) { group in
for url in urls {
group.addTask {
let username = "user-country-\(country)-session-\(UUID().uuidString.prefix(8))"
let token = Data("\(username):pass".utf8).base64EncodedString()
var request = URLRequest(url: url)
request.setValue("Basic \(token)", forHTTPHeaderField: "Proxy-Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
do {
let (data, response) = try await session.data(for: request)
guard let http = response as? HTTPURLResponse,
(200...299).contains(http.statusCode) else {
return nil
}
return try JSONDecoder().decode(PriceResult.self, from: data)
} catch {
print("Fehler bei \(url): \(error)")
return nil
}
}
}
var results: [PriceResult] = []
for try await result in group {
if let result = result {
results.append(result)
}
}
return results
}
}
let urls = [
URL(string: "https://api.shop.example/prices/1")!,
URL(string: "https://api.shop.example/prices/2")!,
URL(string: "https://api.shop.example/prices/3")!
]
Task {
do {
let prices = try await fetchPrices(urls: urls, country: "DE")
for p in prices {
print("\(p.product): \(p.price) \(p.currency)")
}
} catch {
print("Batch-Fehler: \(error)")
}
}
Produktionstipps: TLS, Retry und ATS
URLSessionDelegate für TLS-Validierung
In Produktion müssen Sie TLS-Zertifikate korrekt validieren. Ein URLSessionDelegate, der urlSession(_:didReceive:completionHandler:) für Server-Trust implementiert, stellt sicher, dass die Verbindung zum Proxy die Identität des Ziels nicht kompromittiert. Bei HTTPS über einen HTTP-Proxy bleibt die TLS-Verbindung Ende-zu-Ende zwischen Client und Zielserver — der Proxy sieht nur den CONNECT-Tunnel.
import Foundation
final class SecureProxyDelegate: NSObject, URLSessionDelegate {
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, credential)
} else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPProxy {
let cred = URLCredential(
user: "user-country-US-session-\(UUID().uuidString.prefix(8))",
password: "pass",
persistence: .forSession
)
completionHandler(.useCredential, cred)
} else {
completionHandler(.performDefaultHandling, nil)
}
}
}
Retry mit exponentiellem Backoff
Bei 429- oder 503-Antworten sollten Sie mit exponentiellem Backoff erneut versuchen. Eine einfache Implementierung mit async/await und maximal 5 Versuchen:
import Foundation
enum ProxyError: Error {
case maxRetriesExceeded
case httpError(Int)
}
func fetchWithRetry(
url: URL,
session: URLSession,
maxRetries: Int = 5,
baseDelay: TimeInterval = 1.0
) async throws -> Data {
var attempt = 0
while attempt < maxRetries {
let delay = baseDelay * pow(2.0, Double(attempt))
if attempt > 0 {
try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
}
var request = URLRequest(url: url)
let token = Data("user-country-DE-session-retry-\(attempt):pass".utf8).base64EncodedString()
request.setValue("Basic \(token)", forHTTPHeaderField: "Proxy-Authorization")
do {
let (data, response) = try await session.data(for: request)
if let http = response as? HTTPURLResponse {
if (200...299).contains(http.statusCode) {
return data
}
if http.statusCode == 429 || http.statusCode == 503 {
attempt += 1
continue
}
throw ProxyError.httpError(http.statusCode)
}
} catch {
attempt += 1
if attempt >= maxRetries {
throw ProxyError.maxRetriesExceeded
}
}
}
throw ProxyError.maxRetriesExceeded
}
App Transport Security (ATS)
Apples ATS erfordert TLS 1.2 oder höher für alle Verbindungen. Wenn Ihr Proxy HTTP-CONNECT-Tunnel für HTTPS verwendet, bleibt die TLS-Verbindung Ende-zu-Ende zwischen Client und Zielserver — der Proxy sieht nur den Tunnel. Sie sollten keine ATS-Ausnahmen (NSAllowsArbitraryLoads) für Proxy-Verbindungen benötigen. Weitere Details finden Sie in den ATS-Dokumentationsrichtlinien von Apple.
Proxy-Typen im Vergleich
| Eigenschaft | HTTP/HTTPS Proxy (Port 8080) | SOCKS5 Proxy (Port 1080) |
|---|---|---|
| Protokoll-Support | HTTP, HTTPS (via CONNECT) | TCP, beliebige Protokolle |
| Authentifizierung | Proxy-Authorization-Header oder 407-Challenge | Username/Password im SOCKS-Handshake |
| URLSession-Support | Vollständig über connectionProxyDictionary | Über kCFStreamPropertySOCKSProxy* |
| Geo-Targeting | Im Benutzernamen kodiert | Im Benutzernamen kodiert |
| Latenz-Overhead | Niedrig (~20–50ms) | Minimal (~10–30ms) |
| Typischer Use Case | Web Scraping, API-Aufrufe | TCP-Tunneling, nicht-HTTP-Protokolle |
ProxyHat-spezifische Einrichtung
ProxyHat verwendet einen einfachen Gateway-Ansatz: Verbinden Sie sich mit gate.proxyhat.com auf Port 8080 (HTTP) oder 1080 (SOCKS5). Die Authentifizierung erfolgt über den Benutzernamen, der Geo-Targeting und Session-IDs kodieren kann. Die vollständige Dokumentation finden Sie unter docs.proxyhat.com.
Der ProxyHat-Ansatz ist sprachunabhängig: Das Web-Scraping-Use-Case funktioniert gleichermaßen mit Swift, Python oder Node.js. Für SERP-Tracking können Sie die gleiche Gateway-Adresse mit unterschiedlichen Session-IDs verwenden. Eine Übersicht aller verfügbaren Proxy-Standorte hilft bei der Auswahl der richtigen Geo-Targeting-Parameter. Aktuelle Preise und Pakete finden Sie auf der ProxyHat-Preisseite.
Beachten Sie, dass ProxyHat auch SDKs für Python und Node.js anbietet, die denselben Gateway verwenden. Die in Swift gezeigten Konzepte — connectionProxyDictionary, Proxy-Authorization-Header, Geo-Targeting im Benutzernamen — lassen sich direkt auf andere Sprachen übertragen.
Ethik, Recht und App Store Richtlinien
Beim Swift Web Scraping mit Proxys sollten Sie rechtliche und ethische Grenzen beachten:
- Legitime öffentliche Daten: Scrapen Sie nur öffentlich verfügbare Daten, für die Sie keine Nutzungsbedingungen verletzen.
- CFAA (USA): Der Computer Fraud and Abuse Act kann unbefugten Zugriff auf geschützte Systeme strafbar machen — selbst bei öffentlichen Daten, wenn ToS dies untersagen.
- GDPR (EU): Personenbezogene Daten unterliegen der DSGVO. Verarbeiten Sie keine personenbezogenen Daten ohne Rechtsgrundlage.
- App Store Richtlinien: Apples App Store Review Guidelines verbieten Apps, die Inhalte ohne Zustimmung des Eigentümers scrapen. Bevorzugen Sie offizielle APIs, wenn verfügbar.
- robots.txt: Respektieren Sie
robots.txt-Anweisungen der Ziel-Websites.
Best Practice: Bevorzugen Sie immer offizielle APIs. Wenn eine API verfügbar ist, ist Scraping über Proxys unnötig und potenziell rechtlich riskant. Proxys sind ein Werkzeug für legitime Datensammlung, nicht für Umgehung von Zugriffsbeschränkungen.
Key Takeaways
URLSessionConfiguration.connectionProxyDictionaryist der primäre Weg, Proxys in Swift zu konfigurieren — mitkCFNetworkProxiesHTTP*für HTTP undkCFStreamPropertySOCKSProxy*für SOCKS5.kCFProxyUsernameKeyundkCFProxyPasswordKeysind in URLSession unzuverlässig — verwenden SieProxy-Authorization-Header oderURLSessionDelegate.- Geo-Targeting und Session-IDs werden im Benutzernamen kodiert:
user-country-US-city-newyork-session-abc123. async/awaitmitTaskGroupermöglicht parallele, proxy-basierte Requests mit typischer Latenz von 200–500ms pro Anfrage.- ATS bleibt aktiv — Proxys tunneln HTTPS über CONNECT ohne ATS-Ausnahmen.
- Residential Proxys umgehen Datacenter-IP-Sperren, erfordern aber ethische und rechtliche Sorgfalt gemäß CFAA, GDPR und App Store Guidelines.






