How to upload large files with multipart form in Alamofire? - ios

I am trying to upload two images (10MB and 1MB size) in a POST method with multipart form.
Using Alamofire upload method this way.
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)
}
}
It goes into the failure and prints:
error with alamofire response: URLSessionTask failed with error: The
operation couldn’t be completed. Message too long
Same POST request on Postman works fine so it's not a server issue.
What is a solution to this?
EDIT:
With smaller images (5MB and 1MB) everything works fine.
EDIT 2:
This is the error:
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>" )})

try this to upload all size of images or videos
func upload(){
let URL = "\(Constants.baseURL)\(path)"
let _headers : HTTPHeaders = ["lang" : "language".localized(),"Content-Type": "application/json","jwt" : AuthManager.authKey()]
var params : [String : Any] = [:]
AF.upload(multipartFormData: { [self] (multipartFormData) in
for (key, value) in params {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
let timestamp = NSDate().timeIntervalSince1970
multipartFormData.append(self.VideoFileData, withName: "url", fileName: "\(Date().timeIntervalSince1970).mp4", mimeType: "video/mp4")
}, to: URL, method: .post, headers: _headers).responseJSON{ [self] (response) in
switch response.result{
case .success(let upload):
do {
self.loadingView.hide()
let Lists = try JSONDecoder().decode(StoreDataVideoModel.self, from: response.data!)
print(Lists)
if(Lists.status == 200){
}else{
}
} catch let error{
self.requestStatus(code: -1, Msg: "\(error.localizedDescription)")
}
if response.error != nil{
self.requestStatus(code: -1, Msg: "\(response.error?.localizedDescription ?? "")")
return
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
print("wrong")
self.requestStatus(code: -1, Msg: "\(error.localizedDescription)")
}
}.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of file
print("Upload Progress: \(progress.fractionCompleted)")
})
}

Related

How to upload image to aws pre signed url as multipart data using Alamofire 5?

I am trying to upload an image to the pre-signed AWS URL. I tried with Alamofire 5 upload method which accepts multipartData. I am getting a 403 error with Alamofire 5 multipart upload.
When I try with URLSession it is working properly.
/// Working code
var request: URLRequest = URLRequest(url: requestURL)
request.httpMethod = "PUT"
request.httpBody = image
request.setValue("image/jpeg", forHTTPHeaderField: "Content-Type")
let tasksession: URLSessionDataTask = session.dataTask(with: request, completionHandler: { (response, urlResp, error) in
if let data: Data = response {
do {
let json: [String: Any]? = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
debugPrint("json \(json)")
}
catch {
debugPrint("error \(error)")
}
}
print(response ?? "response nil")
print(error ?? "response nil")
})
tasksession.resume()
Same when I try with AF 5 it is not working
// Not working code.
AF.upload(multipartFormData: { (multiPart) in
multiPart.append(imageData, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
}, to: url, method: .put, headers: ["Content-Type": "image/jpeg"],
])
.uploadProgress(queue: .main, closure: { progress in
//Current upload progress of the file
print("Upload Progress: \(progress.fractionCompleted)")
})
.responseJSON(completionHandler: { data in
let json: [String: Any]? = data as? [String: Any]
debugPrint("upload complete json \(data)")
})
Could someone tell why it is not working with multipart upload with Alamofire 5, multipart upload is working in Android.
Alamofire Version 4.9.1
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
//Any Post Params if you have.
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
}, to:uploadUrlStr) //uploadUrlStr: upload url in your case
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Uploading")
print(CGFloat(progress.fractionCompleted * 100))
})
upload.responseJSON { response in
print("Upload Finished")
guard let resultValue = response.result.value else {
NSLog("Result value in response is nil")
return
}
}
case .failure(let encodingError):
print(encodingError.localizedDescription)
}
}
This is working for me.

Swift 4 Alamofire multipart upload not working

I am using alamofire 4.7 and swift 4
I need to upload image and json to server.
I am using the following code below for uploading bu I am getting result failure but data is inserting in server but not getting response, showing some serialization error as something like this
▿ result : FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
▿ failure : AFError
▿ responseSerializationFailed : ResponseSerializationFailureReason
▿ timeline : Timeline: { "Request Start Time": 548835779.066, "Initial Response Time": 548835779.074, "Request Completed Time": 548835779.127, "Serialization Completed Time": 548835779.127, "Latency": 0.008 secs, "Request Duration": 0.061 secs, "Serialization Duration": 0.000 secs, "Total Duration": 0.061 secs }
- requestStartTime : 548835779.06617701
- initialResponseTime : 548835779.07390201
- requestCompletedTime : 548835779.12704694
- serializationCompletedTime : 548835779.12748504
- latency : 0.0077250003814697266
- requestDuration : 0.060869932174682617
- serializationDuration : 0.00043809413909912109
- totalDuration : 0.061308026313781738
▿ _metrics : Optional<AnyObject>
=================================================================
let auth : String = MitraModal.sharedInstance().getBasicAuthenticationString()
let headers = ["Authorization": auth, "Content-type": "multipart/form-data"]
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append("\(parameters)".data(using: String.Encoding.utf8)!, withName: "data" as String)
if (!imageArray.isEmpty) {
for item in imageArray {
multipartFormData.append(item!, withName: "file", fileName: "image.png", mimeType: "image/png")
}
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
if let JSON = response.result.value
{
print("JSON: \(JSON)")
onCompletion?(JSON as? JSON)
print("Successfully uploaded")
}
if let err = response.error {
onError?(err)
return
}
onCompletion?(nil)
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
onError?(error)
}
}
}
Anyone help ?
As i'm newbie, but Few days ago, i had same problem while uploading image, you must have to accept image by using file on the server side because of your image tag consist withName: "file" .
func AlamofireUploadImages(){
let url : String = URL_IP+"/ZameenServer/api/addNewProperty.php"
for img in HOUSEImages{
let data = UIImageJPEGRepresentation(img, 0.2)!
ImagesData.append(data)
}
let parameters = [
"userId" : "5",
"unit" : "6789"
] //Optional for extra parameter
Alamofire.upload(multipartFormData: { multipartFormData in
for imageData in self.ImagesData {
multipartFormData.append(imageData, withName: "file[]", fileName: self.randomString(length: 5)+".jpeg", mimeType: "image/jpeg")
}
for (key, value) in parameters {
multipartFormData.append((value?.data(using: String.Encoding.utf8)!)!, withName: key)
} //Optional for extra parameters
},
to:url)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON
{
response in
print("Response :\(response.result.value)")
}
case .failure(let encodingError):
print("no Error :\(encodingError)")
}
}
}
NOTE: As i'm uploading array of images so for uploading multile images use withName: "file[]" or for single image use withName: "file"
Might be it helps you.
Thanks
let url = BaseViewController.API_URL + "uploads"
let image = info[UIImagePickerControllerEditedImage] as? UIImage
let imgData = UIImageJPEGRepresentation(image!, 0.2)!
let parameters = [
"user_id" : UserDefaults.standard.value(forKey: "userId")!
]
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imgData, withName: "uload_data",fileName: "file.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
} //Optional for extra parameters
},
to:url)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
self.objHudHide()
print(response.result.value)
let jsonDict : NSDictionary = response.result.value as! NSDictionary
print(jsonDict)
if jsonDict["status"] as! String == "Success"
{
let detailDict : Dictionary = jsonDict["detail"] as! Dictionary<String,Any>
if let getTotalPrice = detailDict["total_price"]
{
self.lblTotalPrice.text = "$ \(getTotalPrice) + Free Shipping"
}
if let getTotalSize = detailDict["total_upload_size"]
{
self.lblTotalSize.text = "Total Size : \(getTotalSize)"
}
}
else
{
let alertViewController = UIAlertController(title: NSLocalizedString("Alert!", comment: ""), message:"Something Went wrong please try again." , preferredStyle: .alert)
let okAction = UIAlertAction(title: NSLocalizedString("Ok", comment: ""), style: .default) { (action) -> Void in
}
alertViewController.addAction(okAction)
self.present(alertViewController, animated: true, completion: nil)
}
}
case .failure(let encodingError):
print(encodingError)
}
}
I get the similar issue as well. This may cause several reasons. In my case that was the error of parameter key of the POST request. When you are executing following line
multipartFormData.append(item!, withName: "file", fileName: "image.png", mimeType: "image/png")
withName:"file" property refers the parameter key (key of the Json request) for the image of the POST request. So you can't use whatever the text you want here. Please add the correct parameter key of the image that your API is referring instead of "file". Let's say API access the image using "fileImage" as the parameter key. So the above line should be something like this.
multipartFormData.append(item!, withName: "fileImage", fileName: "image.png", mimeType: "image/png")

upload image and multiple parameters using multipart in alamofire 4 in swift 4

I am trying to upload image with multiple parameters using alamofire multipart with swift 4 but I can not upload image sucessfully and I got response like
{
"error" : "error uploading file, please retry"
}
Here is my function which I call on upload button event.
// selectedLogo = (info["UIImagePickerControllerOriginalImage"] as? UIImage)!
let imageData = UIImageJPEGRepresentation(selectedLogo, 1.0)
let parameters: Parameters = ["id": strUserId,
"telephone": self.txtTelephoneNumber.text!,
"email": self.txtEmail.text!,
"notice":self.txtNotices.text!,
"status" : userData["status"]]
print(parameters)
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let data = imageData{
multipartFormData.append(data, withName: "club_image", fileName: "file.jpg", mimeType: "image/jpg")
}
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!,withName: key as String)
}
}, to:"\(self.app.strBaseAPI)updatedata.php")
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
//Print progress
print(progress)
})
upload.validate()
upload.responseJSON { response in
if response.response?.statusCode == 200
{
if response.result.isSuccess == true
{
if let value = response.result.value
{
self.json = JSON(value)
print(self.json)
let strStatus : String = self.json["success"].stringValue
if strStatus == "true"
{
Toast(text: strStatus).show()
}else{
Toast(text: strStatus).show()
}
}else{
Toast(text: "Something wrong").show()
}
}else{
Toast(text: "Something wrong").show()
}
}else{
SVProgressHUD.dismiss()
Toast(text: "Something wrong").show()
}
}
case .failure(let encodingError):
//print encodingError.description
print(encodingError.localizedDescription)
}
when I convert image using UIImagePNGRepresentation with same method just change one line
multipartFormData.append(imageData!, withName: "image", fileName:
"image.png", mimeType: "image/png")
it will give me like this
SUCCESS: {
error = "error data post";
}
Please help me!!
There is no such MIME Type as image/jpg. Change it to image/jpeg.
So the error was from the server side, that had a very small size limit for images and that's why they weren't saving. Try to updated the compression for the JPEG images from
if let imageData = UIImageJPEGRepresentation(selectedLogo, 1)
to
if let imageData = UIImageJPEGRepresentation(selectedLogo, 0.6)
Hope this will help you.

Failing While uploading Images By Almofire

I am uploading images in multi-part form data but was not succeed it throwing an error. but I'm trying in postman it succeeded .i don't know where I have done a mistake.i have attached postman screenshot for uploading response.please check it and I'm Using Almofire for responce.
func uploadimages() {
let url = ServiceUrl.Base + "ShopRegistration/ShopPicture"
print("URL === > \(url)")
print(self.imgData?.count)
var token :String = ""
if let strToken = Preference.GetString(key: UserDefaultsKey.Token) {
token = strToken
}
var RequestDist : NSDictionary = NSDictionary()
RequestDist = ["ShopId": "\(Preference.GetInteger(key: UserDefaultsKey.ShopID))"]
as NSDictionary;
print(RequestDist)
if(Reachability.isConnectedToNetwork())
{
Alamofire.upload(multipartFormData: { (multipartFormData) in
if self.imgData != nil && (self.imgData?.count)! > 0 {
for dataImg in (self.imgData)! {
//shopImage
multipartFormData.append(dataImg, withName: "shopImage", fileName: "uploaded_file.jpeg", mimeType: "image/jpeg")
}
}
for (key, value) in RequestDist {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key as! String )
}
print("Request ===>>> /n \(multipartFormData.contentType)")
}, to:url,headers :["authToken" : token])
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (Progress) in
print("\n")
print(Progress.fractionCompleted)
})
upload.responseJSON { response in
if(response.result.isSuccess){
print("\n\n")
print("\(response.result.isSuccess)")
print("\n\n")
print(response.result)
print("\n\n")
print(response)
print("\n\n")
appDelegate.window?.rootViewController?.view.makeToast(message: "Images added sucessfully")
let datastring = NSString(data:response.data!, encoding:String.Encoding.utf8.rawValue) as String?
print("Response:::>>>> \(String(describing: datastring))")
if let intShopID : Int = Preference.GetInteger(key: UserDefaultsKey.ShopID) {
self.getShopImagesCall(intshopID: intShopID)
}
}else{
appDelegate.window?.rootViewController?.view.makeToast(message: AppMessage.getErrorInResponse)
}
}
case .failure(let encodingError):
appDelegate.window?.rootViewController?.view.makeToast(message: AppMessage.getErrorInResponse)
break
}
}
}
}
for JPEG image on network use
let imageData = UIImageJPEGRepresentation(img, 0.5) and at body
multipartFormData.append(dataImg, withName: "shopImage", fileName: "uploaded_file.jpeg", mimeType: "image/jpeg").
for PNG image
let image = UIImagePNGRepresentation(pickedImage) and at body
multipartFormData.append(dataImg, withName: "shopImage", fileName: "uploaded_file.png", mimeType: "image/png").

iOS SwiftHTTP library: Posting text and Uploading images do not work properly

I just gave a try of using the iOS library SwiftHTTP for posting text and uploading images same time, but I got server errors (built in sails.js with skipper). Below is my code:
var questionObj: [String: AnyObject] = [
"title": self.titleTextField.text!,
"content": self.contentTextView.text,
"tags": self.tagsTextField.text!,
"images": [Upload]() // to be populated below
]
var images: [Upload] = []
for i in 0..<self.selectedImageData.count {
// selectedImageData is an array of NSData from UIImage
images.append(Upload(data: self.selectedImageData[i], fileName: "image\(i).png", mimeType: "image/png"))
}
questionObj["images"] = images // assign the array of Upload
Start uploading and posting:
do {
let opt = try HTTP.POST(targetURL, parameters: questionObj, headers: headers)
print("starting to POST question object to remote server")
opt.progress = {progress in
print("progress: \(progress)")
}
opt.start { response in
print("response from server: \(response)")
}
} catch let error {
print("got an error creating the request: \(error)")
}
The above code works only if I don't upload images.
The following code works for me using Alamofire and multipartFormData for posting text and uploading multiple images same time:
Alamofire.upload(.POST, targetURL, headers: headers, multipartFormData: { (multipartFormData) -> Void in
for (key, val) in questionObj {
print("iterating key-val: \(key): \(val) in question JSON")
multipartFormData.appendBodyPart(data: String(val).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name: key)
}
for i in 0..<self.selectedImageData.count {
let img = self.selectedImageData[i] // array of NSData from UIImage
multipartFormData.appendBodyPart(data: img, name: "images", fileName: "file\(i).png", mimeType: "image/png")
}
}, encodingCompletion: { (encodingResult) -> Void in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON(completionHandler: { (response) -> Void in
print("successful response: \(response)")
})
case .Failure(let error):
print("in encoding completion, error: \(error)")
}
})
I guess the reason why SwiftHTTP does not work for me is it does not compose a multipart form for posting and uploading the same time, but I could be wrong, as I just started learning to use SwiftHTTP. Thanks!

Resources