使用Alamofire上傳圖片到阿里OSS時會發現有的時候上傳失敗,原因是因爲Alamofire拼接form-data的時候順序會出錯,所以需要自己使用URLRequest自己進行拼接就可以。
private let MultipartFormCRLF = "\r\n"
private let MutlipartFormCRLFData = MultipartFormCRLF.data(using: String.Encoding.utf8)!
class MutipartDataBuilder {
public let boundary:String
var fields:[Data] = []
public init(){
self.boundary = NSUUID().uuidString
}
public func build()->Data?{
let data = NSMutableData()
for field in self.fields {
data.append(self.toData("--\(self.boundary)"))
data.append(MutlipartFormCRLFData)
data.append(field)
}
data.append(self.toData("--\(self.boundary)--"))
data.append(MutlipartFormCRLFData)
return data.copy() as? Data
}
public func appendFormData(_ key:String,value:String){
let contentDisposition = "Content-Disposition: form-data; name=\"\(encode(key))\""
let data = self.merge([
self.toData(contentDisposition),
MutlipartFormCRLFData,
MutlipartFormCRLFData,
self.toData(value),
MutlipartFormCRLFData
])
self.fields.append(data)
}
public func appendFormData(_ name:String,content:Data,fileName:String,contentType:String){
let contentDisposition = "Content-Disposition: form-data; name=\"\(self.encode(name))\"; filename=\"\(self.encode(fileName))\""
let contentTypeHeader = "Content-Type: \(contentType)"
let data = self.merge([
self.toData(contentDisposition),
MutlipartFormCRLFData,
self.toData(contentTypeHeader),
MutlipartFormCRLFData,
MutlipartFormCRLFData,
content,
MutlipartFormCRLFData
])
self.fields.append(data)
}
fileprivate func encode(_ string:String)->String{
let characterSet = CharacterSet.MIMECharacterSet()
return string.addingPercentEncoding(withAllowedCharacters: characterSet)!
}
fileprivate func toData(_ string:String)->Data{
return string.data(using: String.Encoding.utf8)!
}
fileprivate func merge(_ chunks:[Data])->Data{
let data = NSMutableData()
for chunk in chunks {
data.append(chunk)
}
return data.copy() as! Data
}
}
extension CharacterSet{
static func MIMECharacterSet() -> CharacterSet {
let characterSet = CharacterSet(charactersIn: "\"\n\r")
return characterSet.inverted
}
}
if let url = URL(string: host){
var request:URLRequest = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData, timeoutInterval: 100)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let builder = MutipartDataBuilder()
builder.appendFormData("OSSAccessKeyId", value: accessid)
builder.appendFormData("policy", value: policy)
builder.appendFormData("Signature", value: signature)
builder.appendFormData("key", value: key)
builder.appendFormData("success_action_status", value: success_action_status)
builder.appendFormData("file", content: imgs[self?.count ?? 0], fileName: name, contentType: "image/jpeg")
let body = builder.build()
request.httpBody = body
request.setValue(String(body?.count ?? 0), forHTTPHeaderField: "Content-Length")
request.setValue("multipart/form-data; boundary=\(builder.boundary)", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, uploadRes, error) in
if let err = error{
dPrint("上傳失敗:\(err)")
if let f = upload_failure{
f(nil)
}
}else{
dPrint("上傳成功")
}
})
task.resume()
}