AFNetworking 3 AFMultipartFormData getting bytes data in response - ios

I'm doing this to send images in an array to server:
NSString *string = [NSString stringWithFormat:#"%#/API/Upload",BaseURLString];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:BaseURLString]];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
for(NSData *eachImage in self.fetchedAtt) {
[manager POST:string
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
[formData appendPartWithFormData:eachImage
name:#"image1"];
}
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (responseObject != nil)
{
//NSDictionary *jsonDictionary = responseObject;
NSLog(#"%#",responseObject);
}
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"%#",error.localizedDescription);
}];
}
For now I only send one image to test. And it get responseObject which is bytes data.
<696d6167 65313a20 efbfbdef bfbdefbf bdefbfbd 00104a46 49460001
01000048 00480000 efbfbdef bfbd0058 45786966 00004d4d 002a0000
00080002 01120003 00000001 00010000 efbfbd69 00040000 00010000
00260000 00000003 efbfbd01 00030000 00010001 0000efbf bd020004
00000001 0000001e efbfbd03...
As per the web guy response should be the URL of the image. Web backend is in ASP.NET What am I doing wrong?
UPDATE
If I change the response serializer I get:
Request failed: unacceptable content-type: application/octet-stream
I've even tried this:
NSString *string = [NSString stringWithFormat:#"%#/API/Upload",BaseURLString];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
NSError *error;
for(NSData *eachImage in self.fetchedAtt) {
NSURLRequest *request = [manager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:string parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
//NSString *value = #"qux";
//NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
//[formData appendPartWithFormData:eachImage name:#"image1"];
[formData appendPartWithFileData:eachImage name:#"image1" fileName:#"test.jpg" mimeType:#"image/jpeg"];
} error:&error];
NSURLSessionDataTask *task = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
NSLog(#"%#", error.localizedDescription);
return;
}
NSLog(#"%#", responseObject);
}];
[task resume];
}
But got Request failed: internal server error (500). if I uncomment the appendPartWithFormData and comment other line I get same bytes in responseObject.
More Updates:
We tested it on postman and the image was uploaded successfully. But if I give something in parameter I get
Request failed: unsupported media type (415)

When you upload images, you'd expect some response from the server (just to acknowledge that they were received successfully). Having said that, looking at your hex data, it's curious. What it looks like is:
The "JFIF" and "Exif" references are consistent with a JPEG response. And the image1 looks like it was the name of the image you sent. But this is a very curious response. It's definitely not the URL of the image.
You should contact the web service authors and get details of what precisely they're sending back, because it doesn't conform to standard responses (XML, JSON, etc.).
By the way, your method of uploading the image looks incorrect. You'd usually do something like:
[formData appendPartWithFileData:eachImage
name:#"image1"
fileName:#"test.jpg"
mimeType:#"image/jpeg"];
Clearly, you'd specify the fileName and mimeType to match what the NSData really was. And I'd double check with the author of the web service whether they really want to use a field name of image1 ... that's a little atypical.

Related

Objective-C: How to send a post request with a multidimensional array of type key value

From application, written in Objective (we use AFNetworking), I need to send a POST request, in the body of which - a multidimensional array of the type "key": "value"
We send request this way:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:#“application/json” forHTTPHeaderField:#“Accept”];
[manager.requestSerializer setValue:#“multipart/form-data” forHTTPHeaderField:#“Content-Type”];
[manager POST:url parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
for (UIImage* image in photoArray) {
NSData *dataImage = UIImageJPEGRepresentation(image,1);
[formData appendPartWithFileData:dataImage name:randomString fileName:[NSString stringWithFormat:#“%#.jpeg”,randomString] mimeType:#“image/jpeg”];
}
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(#“!!!!! %#“, responseObject);
if (success) {
[KVNProgress dismiss];
success(responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#“%#“, error.localizedFailureReason);
[KVNProgress showError];
}];
And this way we form NSDictionary:
NSString*name = model.name;
NSString*lat = model.lat;
NSString*lon = model.lon;
NSDictionary* dic = [NSDictionary
dictionaryWithObjectsAndKeys:name,#"name",lat,#"lat",lon,#"lon", nil];
[addressArray addObject:dic];
Here's what we get on Objective
Here is what request the server receives
And here's what should come
How to build an object on Objective so that data [address] came to the HTTP server as indicated in the 3 picture?

How to send a key in parameter in AFMultipartFormData AFNetworking 3

This is how I"m sending the request:
NSString *string = [NSString stringWithFormat:#"%#/API/Upload",BaseURLString];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
NSError *error;
manager.responseSerializer.acceptableContentTypes = nil;
for(NSData *eachImage in self.fetchedAtt) {
NSString *mystring = #"786";
NSURLRequest *request = [manager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:string parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFormData:eachImage name:#"myImage"];
[formData appendPartWithFormData:[mystring dataUsingEncoding:NSUTF8StringEncoding]
name:#"PracticeCode"];
} error:&error];
NSURLSessionDataTask *task = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
NSLog(#"%#", error.localizedDescription);
return;
}
NSLog(#"%#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
}];
[task resume];
}
}
Sometimes I get:
{ "Message": "Error writing MIME multipart body part to output
stream." }
//this is a 500 error
and sometimes I get
Request failed: unsupported media type (415)
You are trying to send multiple files in a single multiform request. Multipart doesn't work like this. You will have to make multiple multipart requests with 1 file at a time. So consider you have 20 files. You will create an async task that takes one file at a time, uploads it, and then performs the same function again for the next files.
And if you want to keep the references, you should return the file ids from the backend, and then append all the ids in a single array and send that array as a param in a separate api request to link the files with any object. Hope that makes sense.
Try this Afnetworking 3.0
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"POST" URLString: [NSString stringWithFormat:#"%#/API/Upload",BaseURLString]; parameters:#{#"text":#"name"} constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageurl]] name:#"bizcard" fileName:#"Businesscard.jpg" mimeType:#"image/jpeg"]; // you file to upload
} error:nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
NSURLSessionUploadTask *uploadTask;
uploadTask = [manager
uploadTaskWithStreamedRequest:request
progress:^(NSProgress * _Nonnull uploadProgress) {
dispatch_async(dispatch_get_main_queue(), ^{
});
}
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
NSLog(#"Error: %#", [[NSString alloc]initWithData:[[error valueForKey:#"userInfo"] valueForKey:#"com.alamofire.serialization.response.error.data"] encoding:NSUTF8StringEncoding]);
callback(NO,nil);
[UtilityClass removeActivityIndicator];
} else {
callback(YES,responseObject);
}
}];
[uploadTask resume];

How To Send NSData with AFNetworking 3 Without Using AFMultipartFormData

I am trying to send wav file as a NSData to rest service with AFNetworking 3. I figured out how to send with AFMultipartFromData but i got an error like that
errorMessage = "Can Not Map Content-Type String multipart/form-data; boundary=Boundary+02588C5 To Media Type ";
When i spoke with the guy who created rest service then he told me i have to send just NSData not anything like AFMultipartFormData. I need some help here because i could not find any way to send "just" NSData.
My code is below;
NSURL *URL = [NSURL URLWithString:#"http://xxxMyService"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPAdditionalHeaders = #{#"xx": #"yy ; zz"};
AFHTTPSessionManager *manager2 = [[AFHTTPSessionManager alloc] initWithBaseURL:URL sessionConfiguration:configuration];
manager2.responseSerializer = [AFJSONResponseSerializer serializer];
//I converted wav file to NSData
NSData *data=[self setVoiceRecordToNSData];
[manager2 POST:#"http://xxxMyService" parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
[formData appendPartWithFileData:data name:#"data" fileName:#"Path.wav" mimeType:#"audio/wav"];
}
progress:nil success:^(NSURLSessionTask *task, id responseObject
{ NSLog(#"JSON: %#", responseObject);}
failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error); }];
Try add this code before POST
manager2.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"multipart/form-data"];

AFNetworking Response Error only for specific URL

Im trying to get response from using GeoNames API. and here my Code
NSMutableDictionary * parameters = [[NSMutableDictionary alloc]initWithDictionary:params];
NSURL *baseURL = [NSURL URLWithString:#"http://api.geonames.org/findNearbyPostalCodesJSON"];
AFHTTPSessionManager * manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:#"" parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
[delegate didReceiveNearByLocationResponse:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"%#",error);
}];
Im getting following error.
Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: forbidden (403)" UserInfo={NSUnderlyingError=0x7ff013d840f0 {Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7ff013d07440> { URL: http://api.geonames.org/findNearbyPostalCodesJSON/ }
i tried with hurl.it to check whether response coming or not. and its coming fine.
Surprise is im using same above code for various other requests with only changing URL and those are working fine.
UPDATED
And previously it worked for the following code. and i did some code quality adjustment and transferred the code to above. then got the problem
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{#"lat": lat,
#"lng": lon,
#"username" : #"testing"
};
[manager POST:#"http://api.geonames.org/findNearbyPostalCodesJSON" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
}
When I just enter the URL http://api.geonames.org/findNearbyPostalCodesJSON into a browser, I get the following JSON:
{"status":{"message":"Please add a username to each call in order for geonames to be able to identify the calling application and count the credits usage.","value":10}}
So I suspect that, at the very least, you need to change your 'POST' to a 'GET':
[manager GET:#"" parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
[delegate didReceiveNearByLocationResponse:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"%#",error);
}];
Beyond that, based on the returned content, it looks like you'll need some additional application-level logic to provide user identification/authentication in order to get the actual data you're interested in, but the above change should at least trigger an invocation of the success block.
I found the solution. i even upgraded the AFNetworking to 3.0 from 2.X
and Code Changed like below. Special Changes GET
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager GET:#"http://api.geonames.org/findNearbyPostalCodesJSON" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(#"success!");
[delegate didReceiveNearByLocationResponse:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"error: %#", error);
}];
"Request failed: unacceptable content-type: text/html"
because the AFNetworking only support #"application/json", #"text/json", #"text/javascript"
you should add a #"text/html" type
[manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
NSMutableDictionary * parameters = [[NSMutableDictionary alloc]initWithDictionary:params];
NSURL *baseURL = [NSURL URLWithString:#"http://api.geonames.org/findNearbyPostalCodesJSON"];
AFHTTPSessionManager * manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
//insert this code
[manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
[manager POST:#"" parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
[delegate didReceiveNearByLocationResponse:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"%#",error);
}];

Nested Json with multipart/form-data in AFNetworking 2.x

I am trying to send nested json with an image from my ios app using AFNetworking library.I am able to send the json data and image successfully but in server the json structure is coming differently.
HTTP request inside my app :-
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{#"requestData":#{#"username":#"200OK",#"password":#"password"}};
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:Self_URL
parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"file"
fileName:#"file"
mimeType:#"image/jpeg"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
So in my django server I am expecting the params as a dictionary same as params but request.POST is coming as
content_type---> multipart/form-data; boundary=Boundary+247685AB6DF2B3BA
<QueryDict: {'requestData[password]': [u'password'], 'requestData[username]': [u'200OK']}>
How can I send json data so that it will be easy to access from server ?
Anything I am missing or what is going wrong?
constructingBodyWithBlock is overriding your AFJSONRequestSerializer and your dictionary is encoded as form data. There is no way to have two content types (multipart/form-data and application/json) for a request at the same time, so you'll have to do this another way.
One possibility is to encode the JSON as an NSData object and append it to the multipart form along with the image data:
NSError *error = nil;
NSData *paramData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
[formData appendPartWithFileData:paramData
name:#"params"
filename:#"params"
mimeType:#"application/json"]
You can access the serialized parameters through request.FILES['params']. Despite the mime-type, I doubt that django will automatically parse the JSON data into a dictionary, but you could do that manually with json.loads.
In AFNetworking3.0, you can introduce JSON in a form using the appendPartWithFormData function
[formData appendPartWithFormData:params name:#"params"];
On the server side, you can access the serialized data using json.loads() on the object. Here is a full snippet from some code I wrote:
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"POST"
URLString:requestUrl parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFormData:[self dictToJson:params] name:#"params"];
[formData appendPartWithFileData:fileData name:fileGeneralName fileName:fileName mimeType:mimeType];
} error:nil];
[[manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse* response, id responseObject, NSError* error) {
[self callCompletionBlock:responseObject withError:error withResponse:response completionHandler:completionBlock];
}] resume];
There's a serialization function in that snippet, which I'll also paste for completion:
+(NSData*)dictToJson:(NSDictionary*)dict {
NSError* error = nil;
return [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error]; }

Resources