Swift中使用URLSession时如何阻止自动重定向?
问题分析与解决:Swift URLSession无法阻止302重定向
核心问题所在
你的代码里有两个关键错误导致代理方法从未触发:
1. 代理方法签名错误
你实现的URLSession(session:task:willPerformHTTPRedirection:newRequest:completionHandler:)是Objective-C风格的方法名,但在Swift中,URLSession的代理方法必须遵循Swift标准签名,正确的方法应该是:
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) { print("PASSING") completionHandler(nil) // 阻止重定向 }
系统只会调用符合官方签名的代理方法,旧的命名方式不会被识别。
2. 代理对象被提前释放
你在makeRequest方法里把myDelegate声明为局部变量,而URLSession对代理的引用是弱引用。当makeRequest方法执行完毕后,局部变量myDelegate会被ARC自动释放,导致代理对象不存在,后续的重定向事件无法触发代理方法。
修正后的完整代码
class MySession: NSObject, URLSessionTaskDelegate { // 修正后的代理方法签名 func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) { print("PASSING") completionHandler(nil) // 阻止自动重定向,返回原302响应 } } class MappingHandler: NSObject { // 把代理对象提升为类属性,保持强引用 private var sessionDelegate: MySession? func makeRequest(urlString: String, method: String, headers: [String: String]?, body: String?, completion: @escaping ([UInt8]?, Int?, [String: Any]?, Error?) -> Void) { guard let url = URL(string: urlString) else { completion(nil, nil, nil, NSError(domain: "Invalid URL", code: -1, userInfo: nil)) return } var request = URLRequest(url: url) request.httpMethod = method request.httpShouldHandleCookies = false request.cachePolicy = .reloadIgnoringLocalCacheData if let headers = headers { for (key, value) in headers { request.setValue(value, forHTTPHeaderField: key) } } let configuration = URLSessionConfiguration.default configuration.timeoutIntervalForRequest = 20.0 configuration.timeoutIntervalForResource = 20.0 if method == "POST" { sessionDelegate = MySession() request.httpBody = body!.data(using: .utf8)! request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") } let session = URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) let task = session.dataTask(with: request) { [weak self] data, response, error in guard let httpResponse = response as? HTTPURLResponse else { completion(nil, nil, nil, error) return } let statusCode = httpResponse.statusCode let responseHeaders = httpResponse.allHeaderFields as? [String: String] if let responseData = data { let byteArray = [UInt8](responseData) completion(byteArray, statusCode, responseHeaders, nil) } else { completion(nil, statusCode, responseHeaders, nil) } // 任务完成后释放代理对象,避免内存泄漏 self?.sessionDelegate = nil } task.resume() } }
额外说明
- 不需要同时实现
URLSessionDelegate,URLSessionTaskDelegate已经包含重定向相关方法,仅实现该协议即可。 - 在
dataTask闭包中使用[weak self]避免循环引用,任务完成后手动释放sessionDelegate,防止内存泄漏。
内容的提问来源于stack exchange,提问作者user22331356
相关产品推荐
相关产品推荐

