如何将获取Cookie的Python HTTP POST脚本转为Swift?遇Cookie为空问题
问题分析与解决方案
你的Swift代码无法获取Cookie的核心原因是请求体格式不匹配,同时还存在HTTPS证书验证和请求头的小问题,以下是具体修正方案:
核心问题点
- 请求体格式错误:你设置了
Content-Type为application/x-www-form-urlencoded,但实际用JSONSerialization生成了JSON格式的请求体,服务器无法解析登录参数,导致认证失败,自然不会返回Cookie。 - HTTPS证书验证:Python代码关闭了证书验证(
verify=False),但Swift默认会严格验证HTTPS证书,内网自签名证书环境下需要手动忽略验证。 - 请求头不一致:Swift中设置的
Accept: application/json与Python的默认Accept: */*不符,可能导致服务器返回非预期内容。
修正后的Swift代码
import Foundation // 辅助函数:将字典转换为x-www-form-urlencoded格式的请求体 func convertToFormData(parameters: [String: String]) -> Data? { let queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) } var components = URLComponents() components.queryItems = queryItems return components.query?.data(using: .utf8) } // 用于忽略自签名证书的Delegate(仅测试/内网环境使用) class SelfSignedCertificateDelegate: 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 { completionHandler(.performDefaultHandling, nil) } } } // 主逻辑 let auth_login = "someName" let auth_password = "somePassword" guard let url = URL(string: "https://192.168.0.1/passport?mode=auth") else { print("无效URL") exit(1) } var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("*/*", forHTTPHeaderField: "Accept") // 与Python requests默认请求头对齐 request.httpMethod = "POST" let parameters = [ "from": "passport", "retpath": "https://192.168.0.1/passport?mode=passport", "passwd": auth_password, "login": auth_login, "display": "page" ] // 使用表单编码生成请求体(替代JSON序列化) request.httpBody = convertToFormData(parameters: parameters) // 配置支持Cookie管理和证书忽略的URLSession let configuration = URLSessionConfiguration.default configuration.httpCookieStorage = HTTPCookieStorage.shared let session = URLSession(configuration: configuration, delegate: SelfSignedCertificateDelegate(), delegateQueue: nil) let task = session.dataTask(with: request) { data, response, error in if let error = error { print("请求错误: \(error.localizedDescription)") return } guard let httpResponse = response as? HTTPURLResponse else { print("无效服务器响应") return } // 打印状态码,快速判断认证是否成功 print("响应状态码: \(httpResponse.statusCode)") // 从响应头解析Cookie if let headerFields = httpResponse.allHeaderFields as? [String: String] { let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url) print("\n从响应头获取的Cookie:") cookies.forEach { print("\($0.name): \($0.value)") } } // 从全局Cookie存储获取(URLSession会自动管理Cookie) if let storedCookies = HTTPCookieStorage.shared.cookies(for: url) { print("\n已存储的Cookie:") storedCookies.forEach { print("\($0.name): \($0.value)") } } // 处理非2xx状态码,打印服务器返回的错误信息 guard (200...299).contains(httpResponse.statusCode) else { print("\n认证失败") if let data = data, let responseText = String(data: data, encoding: .utf8) { print("服务器错误响应: \(responseText)") } return } print("\n认证成功") } task.resume() // 保持程序运行(命令行环境需要) RunLoop.main.run(until: Date().addingTimeInterval(10))
关键修正说明
- 表单编码请求体:用
convertToFormData函数将参数转换为与Pythonrequests.post(data=...)完全一致的x-www-form-urlencoded格式,确保服务器能正确解析登录参数。 - 证书验证处理:添加
SelfSignedCertificateDelegate类忽略自签名证书验证,对应Python的verify=False(注意:生产环境禁止使用此逻辑)。 - 请求头对齐:将
Accept头改为*/*,与Python requests的默认行为一致,避免服务器因请求头不符合预期而拒绝。 - 增强错误排查:添加响应内容打印,方便查看服务器返回的具体错误(比如用户名密码错误提示)。
内容的提问来源于stack exchange,提问作者RaduMod
相关产品推荐
相关产品推荐

