Swift使用带认证代理时出现HTTP 400错误请求问题求助
Swift代理请求返回HTTP 400 Bad Request问题排查与解决
问题概述
在Swift中使用带认证的HTTP代理,通过NWConnection已成功建立与代理服务器的连接,但向httpbin.org发送请求时收到HTTP/1.1 400 Bad Request响应,需排查请求格式问题。
错误响应
Connected to proxy: resi.wealthproxies.com Response from proxy resi.wealthproxies.com: HTTP/1.1 400 Bad Request Server: awselb/2.0 Date: Thu, 13 Feb 2025 21:31:28 GMT Content-Type: text/html Content-Length: 122 Connection: close <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> </body> </html>
实现代码
func averageProxyGroupSpeed(proxies: [String], completion: @escaping (Int, String) -> Void) { let numProxies = proxies.count if numProxies == 0 { completion(0, "No proxies") return } var totalTime: Int64 = 0 var successCount = 0 let group = DispatchGroup() let queue = DispatchQueue(label: "proxyQueue", attributes: .concurrent) let lock = NSLock() let shuffledProxies = proxies.shuffled() let selectedProxies = ["resi.wealthproxies.com:8000:akzaidan:x0if46jo-country-US-session-niwtz2y7-duration-60"] for proxy in selectedProxies { group.enter() queue.async { let proxyDetails = proxy.split(separator: ":").map(String.init) guard proxyDetails.count == 4, let port = UInt16(proxyDetails[1]) else { completion(0, "Invalid proxy format") group.leave() return } let proxyEndpoint = NWEndpoint.hostPort(host: .init(proxyDetails[0]), port: NWEndpoint.Port(integerLiteral: port)) let proxyConfig = ProxyConfiguration(httpCONNECTProxy: proxyEndpoint, tlsOptions: nil) proxyConfig.applyCredential(username: proxyDetails[2], password: proxyDetails[3]) let parameters = NWParameters.tcp let privacyContext = NWParameters.PrivacyContext(description: "ProxyConfig") privacyContext.proxyConfigurations = [proxyConfig] parameters.setPrivacyContext(privacyContext) let connection = NWConnection(to: .hostPort(host: "httpbin.org", port: 80), using: parameters) let start = Date() connection.stateUpdateHandler = { state in switch state { case .ready: print("Connected to proxy: \(proxyDetails[0])") let httpRequest = """ GET http://httpbin.org/get HTTP/1.1\r\n Host: httpbin.org\r\n Connection: close\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Encoding: gzip, deflate\r\n Accept-Language: en-US,en;q=0.9\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15\r\n \r\n """ connection.send(content: httpRequest.data(using: .utf8), completion: .contentProcessed({ error in if let error = error { print("Failed to send request: \(error)") group.leave() } else { // Receive the response connection.receive(minimumIncompleteLength: 1, maximumLength: 4096) { data, _, isComplete, error in defer { group.leave() } if let error = error { print("Failed to receive response: \(error)") } else if isComplete { print("complete") if let data { let responseString = String(data: data, encoding: .utf8) ?? "" print("Response from proxy \(proxyDetails[0]): \(responseString)") } else { print("data len is \(data?.count ?? -6)") } let duration = Date().timeIntervalSince(start) * 1000 // Convert to milliseconds lock.lock() totalTime += Int64(duration) successCount += 1 lock.unlock() } else if let data { let responseString = String(data: data, encoding: .utf8) ?? "" print("Response from proxy \(proxyDetails[0]): \(responseString)") } else { print("Not complete") } } } })) case .failed(let error): print("Connection failed for proxy \(proxyDetails[0]): \(error)") group.leave() case .cancelled: print("Connection cancelled for proxy \(proxyDetails[0])") group.leave() case .waiting(let error): print("Connection waiting for proxy \(proxyDetails[0]): \(error)") group.leave() default: break } } connection.start(queue: queue) } } group.notify(queue: DispatchQueue.main) { if successCount == 0 { completion(0, "Proxies Failed") } else { let averageTime = Int(Double(totalTime) / Double(successCount)) completion(averageTime, "") } } }
问题原因与解决方法
核心问题:HTTP请求格式错误
你构造的多行HTTP请求字符串中,每行开头包含了代码缩进带来的多余空格,导致实际发送的请求行和请求头前面存在无效空格,触发代理服务器的400错误。
另外,对于HTTP代理(目标端口为80),请求行使用相对路径(GET /get HTTP/1.1)比完整URL更规范,部分代理服务器可能对此有严格要求。
修正后的HTTP请求构造
将请求字符串改为无缩进的格式,或使用字符串拼接避免多余空格:
let httpRequest = "GET /get HTTP/1.1\r\n" + "Host: httpbin.org\r\n" + "Connection: close\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "Accept-Language: en-US,en;q=0.9\r\n" + "Upgrade-Insecure-Requests: 1\r\n" + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15\r\n" + "\r\n"
或者使用多行字符串时去掉所有缩进:
let httpRequest = """ GET /get HTTP/1.1\r\n Host: httpbin.org\r\n Connection: close\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Encoding: gzip, deflate\r\n Accept-Language: en-US,en;q=0.9\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15\r\n \r\n """
其他注意点
- 确认代理服务器支持HTTP代理模式(你当前使用的
httpCONNECTProxy是用于HTTPS的CONNECT方法,若目标是HTTP,部分代理可能需要调整配置,但从连接成功来看,认证是有效的,主要问题还是请求格式)。 - 若后续请求HTTPS目标,需使用
CONNECT方法建立隧道,但当前目标是HTTP,直接发送普通HTTP请求即可。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

