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

如何在Alamofire中通过Multipart Form上传大文件?

解决Alamofire多表单上传大文件报"Message too long"错误

问题描述

尝试通过POST请求的Multipart Form方式上传两张图片(10MB和1MB),使用Alamofire的upload方法实现,代码如下:

AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(InputStream(data: imageMedia.data), // 10MB data
                         withLength: UInt64(imageMedia.data.count),
                         name: imageMedia.type.rawValue,
                         fileName: imageMedia.filename,
                         mimeType: imageMedia.mimeType)

multipartFormData.append(InputStream(data: maskMedia.data), // 1MB data
                         withLength: UInt64(maskMedia.data.count),
                         name: maskMedia.type.rawValue,
                         fileName: maskMedia.filename,
                         mimeType: maskMedia.mimeType)
}, with: request).responseData { afDataResponse in
    switch afDataResponse.result {
    case .success(let data):
        completion(data)
    case .failure(let error):
        print("error with alamofire response \(error.localizedDescription)")
        completion(nil)
    }
}

请求执行失败,报错信息:

error with alamofire response: URLSessionTask failed with error: The operation couldn’t be completed. Message too long

补充信息:

  • 相同请求在Postman中可正常执行,排除服务器问题
  • 使用较小图片(5MB+1MB)时上传正常

详细错误日志:

sessionTaskFailed(error: Error Domain=NSPOSIXErrorDomain Code=40 "Message too long"
UserInfo={_NSURLErrorFailingURLSessionTaskErrorKey=LocalUploadTask <8F7404DD-2947-4B18-9F23-C23F0483F440>.<1>,
_kCFStreamErrorDomainKey=1, NSErrorPeerAddressKey=<CFData 0x600001068280 [0x1b9553c60]>{length = 16, capacity = 16, bytes =
0x100201bbd8ef26350000000000000000}, _kCFStreamErrorCodeKey=40,
_NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalUploadTask <8F7404DD-2947-4B18-9F23-C23F0483F440>.<1>")})

问题原因

iOS的URLSession默认会将整个请求体加载到内存中处理,当请求体大小超过系统阈值(通常约8MB)时,就会触发Message too long错误。Postman会自动启用分块上传,而Alamofire默认配置未针对性处理大文件场景。

解决方案

1. 优先采用文件URL直接上传(最优解)

避免将图片数据加载到内存,直接使用本地文件URL构建表单,Alamofire会自动采用流式上传,不占用大量内存:

// 假设imageMedia和maskMedia持有图片的本地文件URL
AF.upload(multipartFormData: { multipartFormData in
    if let imageFileURL = imageMedia.fileURL {
        multipartFormData.append(imageFileURL,
                                 withName: imageMedia.type.rawValue,
                                 fileName: imageMedia.filename,
                                 mimeType: imageMedia.mimeType)
    }
    if let maskFileURL = maskMedia.fileURL {
        multipartFormData.append(maskFileURL,
                                 withName: maskMedia.type.rawValue,
                                 fileName: maskMedia.filename,
                                 mimeType: maskMedia.mimeType)
    }
}, with: request)
.responseData { afDataResponse in
    switch afDataResponse.result {
    case .success(let data):
        completion(data)
    case .failure(let error):
        print("error with alamofire response \(error.localizedDescription)")
        completion(nil)
    }
}

2. 启用分块传输编码

修改请求配置,强制开启HTTP分块传输,让请求体分块发送,避免一次性加载到内存:

var request = request // 原请求实例
request.setValue("chunked", forHTTPHeaderField: "Transfer-Encoding")

AF.upload(multipartFormData: { multipartFormData in
    // 原表单构建代码
}, with: request)
.responseData { afDataResponse in
    // 原响应处理代码
}

3. 调整Session内存阈值

如果必须使用内存数据,可以修改Alamofire Session的配置,增大请求体内存阈值,超过阈值时自动写入磁盘处理:

let configuration = URLSessionConfiguration.default
// 设置内存阈值为20MB,超过则写入磁盘
configuration.httpMaximumConnectionsPerHost = 5
configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
configuration.urlCache = nil

let session = Session(configuration: configuration)

session.upload(multipartFormData: { multipartFormData in
    // 原表单构建代码
}, with: request)
.responseData { afDataResponse in
    // 原响应处理代码
}

验证建议

优先测试第一种方案(文件URL上传),该方案稳定性最高且内存占用最低,可直接解决大文件上传的内存溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 20:01:03