You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:05:23