本文探索一下Alamofire
多表单上传的实现
SessionManager.default
.upload(multipartFormData: { (formData) in
formData.append("lili".data(using: .utf8)!, withName: "name")
formData.append("22".data(using: .utf8)!, withName: "age")
}, to: url) { (result) in
switch result {
case .failure(let error):
print(error)
case .success(let upload, _, _):
upload.response(completionHandler: { (response) in
print(response)
})
}
}
首先看一下formData.append
做了什么
- 拼接一个header
var disposition = "form-data; name=\"\(name)\""
if let fileName = fileName { disposition += "; filename=\"\(fileName)\"" }
var headers = ["Content-Disposition": disposition]
if let mimeType = mimeType { headers["Content-Type"] = mimeType }
return headers
- 处理data
let stream = InputStream(data: data)
let length = UInt64(data.count)
append(stream, withLength: length, headers: headers)
- 生成
model:BodyPart
,保存model
到bodyParts
let bodyPart = BodyPart(headers: headers, bodyStream: stream, bodyContentLength: length)
bodyParts.append(bodyPart)
其次,看看upload
做了什么数据处理
如果formData.contentLength < encodingMemoryThreshold && !isBackgroundSession
则是内存数据上传
一:内存数据上传
- 设置
Content-Type
urlRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: "Content-Type")
- formData数据处理
public func encode() throws -> Data {
if let bodyPartError = bodyPartError {
throw bodyPartError
}
var encoded = Data()
bodyParts.first?.hasInitialBoundary = true
bodyParts.last?.hasFinalBoundary = true
for bodyPart in bodyParts {
let encodedData = try encode(bodyPart)
encoded.append(encodedData)
}
return encoded
}
这里是对bodyParts
里的模型数据进行处理,最后拼接成Data
数据,作为httpBody数据上传,其中需要注意点是bodyPart.bodyStream
,是以流数据的形式上传,避免内存过高问题。具体代码不在上传
- 生成MultipartFormDataEncodingResult 枚举对象,
upload
开始上传数据
let encodingResult = MultipartFormDataEncodingResult.success(
request: self.upload(data, with: urlRequestWithContentType),
streamingFromDisk: false,
streamFileURL: nil
)
生成UploadRequest
,开始上传数据
private func upload(_ uploadable: UploadRequest.Uploadable) -> UploadRequest {
do {
let task = try uploadable.task(session: session, adapter: adapter, queue: queue)
let upload = UploadRequest(session: session, requestTask: .upload(uploadable, task))
if case let .stream(inputStream, _) = uploadable {
upload.delegate.taskNeedNewBodyStream = { _, _ in inputStream }
}
delegate[task] = upload
if startRequestsImmediately { upload.resume() }
return upload
} catch {
return upload(uploadable, failedWith: error)
}
}
- 主线程异步回调上传结果
(queue ?? DispatchQueue.main).async { encodingCompletion?(encodingResult) }