iOS-阿里OSS Alamofire圖片上傳,失敗原因和小實例

使用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()
                        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章