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

Swift中Multipart接口响应极慢问题排查求助

问题排查:Swift中Multipart接口请求极慢但Postman正常

我的网络状态正常,使用Postman请求目标接口时响应很快,但在Swift代码中调用同一个接口却需要5分钟才返回结果。尝试过多种优化手段仍未解决问题,以下是Multipart请求的封装代码及调用代码,恳请帮忙排查问题根源。

封装代码

class APINetworkManagerMultipart: NSObject {
    static let sharedInstance = APINetworkManagerMultipart()
    
    fileprivate override init() {
        super.init()
    }
    func serviceCallWithMultipartFormData<T: Codable>(
        url: URL,
        headers: [String: String]?,
        parameters: [String: Any],
        completion: @escaping (Result<T, Error>) -> Void
    ) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        let token = "Bearer mytoken"
        request.setValue(token, forHTTPHeaderField: "Authorization")
        
        let boundary = "Boundary-\(UUID().uuidString)"
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        
        let body = NSMutableData()
        
        for (key, value) in parameters {
            if let stringValue = value as? String {
                body.append("--\(boundary)\r\n".data(using: .utf8)!)
                body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
                body.append("\(stringValue)\r\n".data(using: .utf8)!)
            }
            else if let data = value as? Data {
                
                body.append("--\(boundary)\r\n".data(using: .utf8)!)
                body.append("Content-Disposition: form-data; name=\"\(key)\"; filename=\"file\"\r\n".data(using: .utf8)!)
                body.append("Content-Type: application/octet-stream\r\n\r\n".data(using: .utf8)!)
                body.append(data)
                body.append("\r\n".data(using: .utf8)!)
            }
        }
        
        body.append("--\(boundary)--\r\n".data(using: .utf8)!)
        request.httpBody = body as Data
        
        if let customHeaders = headers {
            for (key, value) in customHeaders {
                request.setValue(value, forHTTPHeaderField: key)
            }
        }
        DispatchQueue.global(qos: .background).async {
            
            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                if let error = error {
                    completion(.failure(error))
                    return
                }
                guard let data = data else {
                    completion(.failure(error!))
                    return
                }
                do {
                    let decodedData = try JSONDecoder().decode(T.self, from: data)
                    completion(.success(decodedData))
                } catch {
                    completion(.failure(error))
                }
            }
            task.resume()
        }
    }
} 

调用代码

func genericFormdataCall(){
    let urlStr = URL(string: "https://prg-name/dev/api/student/edit-profile")!
    let parameters: [String: Any] = [
        "dob": "2005-07-24",
        "name": "Student",
        "gender": "M",
        "school_location": "TestLocation",
        "school_name": "K V",
        "grade": "12th grade",
        "student_bio": "I am a student",
        "profile_pic": nil
    ] as! [String : Any]
    
    DispatchQueue.global().async {
        
        APINetworkManagerMultipart.sharedInstance.serviceCallWithMultipartFormData(url: urlStr, headers: nil, parameters: parameters) { (result: Result<MultipartModel, Error>) in
            switch result {
            case .success(let response):
                // Handle the successful response
                self.formdataResponse = response
                print("Response: \(response)")
            case .failure(let error):
                // Handle the error
                print("Error: \(error)")
            }
        }
    }
}

问题分析及修复建议

1. 参数中nil值未处理导致请求格式异常

调用代码里的profile_pic参数为nil,但封装代码没有处理nil的逻辑,直接跳过该参数。而Postman会自动忽略空值或按服务器预期的格式传递空字段,服务器端可能因缺少该参数或解析异常,一直处于等待状态导致超时。

  • 修复方案:
    • 移除参数中的nil键值对;
    • 或在封装代码中添加nil处理逻辑,比如传递空字符串:
      else if value is NSNull || value == nil {
          body.append("--\(boundary)\r\n".data(using: .utf8)!)
          body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
          body.append("\r\n".data(using: .utf8)!)
      }
      

2. 手动拼接Multipart格式易出错

手动构建Multipart请求体容易出现换行符、边界符拼接错误,服务器端解析时卡住。建议使用URLSession原生的MultipartFormData类构建请求体,避免格式错误。

3. 不必要的线程嵌套

封装代码已在后台队列执行dataTask,调用代码又额外嵌套了一层DispatchQueue.global().async,会增加线程调度开销,建议去掉外层异步调用。

4. 添加合理的请求超时设置

默认URLRequest超时时间较长,可手动设置合理超时,避免长时间无意义等待:

var request = URLRequest(url: url)
request.timeoutInterval = 30 // 设置30秒超时

内容的提问来源于stack exchange,提问作者Swift

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 09:15:25