In AFNetworking, difference between httpbody and parameter post request? - afnetworking

First with httpbody:
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSMutableURLRequest *req = [[AFJSONRequestSerializer serializer] requestWithMethod:#"POST" URLString:#"url" parameters:nil error:nil];
req.timeoutInterval= [[[NSUserDefaults standardUserDefaults] valueForKey:#"timeoutInterval"] longValue];
[req setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[req setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[req setHTTPBody:da];
[[manager dataTaskWithRequest:req completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (!error) {
NSLog(#"Reply JSON: %#", responseObject);
} else {
NSLog(#"Error: %#, %#, %#", error, response, responseObject);
}
}] resume];
Second with parameter:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[manager POST:#"https://exmaple.com/post.php" parameters:json progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"Error: %#", error);
}];
What is the different between this two post method? I notice one different is parameter one will use url encoding method to encode data while the other will pass the raw data.

The first method is intended for situations where you are passing a single blob of raw data to the server. Use this for:
Sending a blob of JSON data to a CGI that expects JSON data
Sending pre-encoded body data in URL-encoded or form-data-encoded format
The file data in a PUT request sent to a server that supports WebDAV.
The second method (providing a series of parameters) is intended to emulate form submission by providing the body data as a series of URL-encoded key-value pairs. For most non-JSON-based CGI work, this is the one you want.
The decision of which one to use is largely determined by what happens on the server side. If the script expects the body data to be a blob of JSON, encode the JSON data to an NSData object and send it as the body data. If the script expects the results of an HTML form, use the other approach. If the script doesn't care, use whichever approach sends less data on average. :-)

Related

Added header in network request using AFNetworking not working

I use the following code to make a GET request including a header Authorization but does not seem to work...the get request does not include the authorization token. Any ideas?
// 1 - define resource URL
NSURL *URL = [NSURL URLWithString:#"https://myurl"];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
[requestSerializer setValue:[NSString stringWithFormat:#"Bearer %#",Token] forHTTPHeaderField:#"Authorization"];
manager.requestSerializer = requestSerializer;
//3 - set a body
NSDictionary *body =#{#"email":#"a#gmail.com"};
//4 - create request
[manager GET:URL.absoluteString
parameters:body
progress:nil
//5 - response handling
success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *responseObject) {
NSLog(#"Reply POST JSON: %#", responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"error on machine token: %#", error);
}
];

AFNetworking 3 AFMultipartFormData getting bytes data in response

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.

AFNetworking 3.0 The data couldn’t be read because it isn’t in the correct format

There are other questions with similar titles but none of them helped me. I've to send a PUT request to server in order to change the status of appointment so I've made this method -(void)appointmentStatusChangedTo:(NSString *)statusID atAppointmentID:(NSString *)appointmentID In which I'm setting the URL and Parameters as
NSString *string = [NSString stringWithFormat:#"%#/API/Appointments/3",BaseURLString];
NSDictionary *para = #{
#"AppointmentStatusId":statusID,
#"ID":appointmentID
};
Then I've made URL request as
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSMutableURLRequest *req = [[AFJSONRequestSerializer serializer] requestWithMethod:#"PUT" URLString:string parameters:para error:nil];
After that I'm setting the header for an authorization token as
NSString *token = [NSString stringWithFormat:#"Bearer %#",[[NSUserDefaults standardUserDefaults] objectForKey:#"userToken"]];
[req setValue:token forHTTPHeaderField:#"Authorization"];
So finally I'm calling it as
[[manager dataTaskWithRequest:req completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error){
if (!error) {
if (response) {
NSLog(#"Respose Object: %#",responseObject);
[self.patientsAppointmentsTableView reloadData];
}
}
else {
// NSLog(#"Error: %#, %#, %#", error, response, responseObject);
NSLog(#"Error: %#", error.localizedDescription);
}
}] resume];
Now it is successfully sending the data to the server but as a response I'm getting
Error: The data couldn’t be read because it isn’t in the correct
format.
I am not sure what the response might look like at the moment as I'm not in contact with backend guy. But as far as I remember it was just a simple 1. SO kindly tell me how to handle any type of response using AFNetworking 3.0 or any change in my code.
try to use below code:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setStringEncoding:NSUTF8StringEncoding];
manager.requestSerializer=serializer;
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
Try following code using Afnetworking 3.0
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager GET:url parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"%#",responseObject);
self.responseHandlers(YES,responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
self.responseHandlers(NO,nil);
}];

iOS Get JSON response from AFNetworking HTTP POST method with JSON parameters

I am getting a 404 error while posting with JSON parameters at the https://api.hackerearth.com/codemonk/v1/topic­detail/. The server uses POST HTTP method to get a topic's details & JSON response is expected when successful. The POST parameter is id of the topic object. POST Parameters are expected to be in JSON.
I am using AFNetworking as follows -
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *params = [NSDictionary dictionaryWithObject:#1 forKey:#"id"];
NSString *str = #"https://api.hackerearth.com/codemonk/v1/topic­-detail/";
NSString *encodedStr = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[manager POST:encodedStr
parameters:params
success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(#"responseObject : %#",responseObject);
} failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
NSLog(#"error : %#", error.localizedDescription);
}];
This is regular stuff but don't know why I can't seem to get it correct now. I am only getting a 404 Page Not Found error. This is not a server side issue for sure. Any help guys ?
Maybe this will help.
AFJSONRequestSerializer *requestSerializer = [AFJSONRequestSerializer serializer];
[requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
operationManagerInstance.requestSerializer = requestSerializer;
=============UPDATE
I have 404 when copying your URL. It's because hyphen symbol between topic-detail is not actually hyphen. It's some special character that doesn't work.
https://api.hackerearth.com/codemonk/v1/topic­-detail/
Instead I deleted it and typed hyphen manually and it works fine.
Remove the following line
NSString *encodedStr = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Try the following:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *params = [NSDictionary dictionaryWithObject:#1 forKey:#"id"];
NSString *str = #"https://api.hackerearth.com/codemonk/v1/topic­-detail/";
[manager POST:str
parameters:params
success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(#"responseObject : %#",responseObject);
} failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
NSLog(#"error : %#", error.localizedDescription);
}];

Waiting for multipart image sending get completed

I'm impementing an application in iOS7, it's kind of a social network app with posts with images and a backend that saves all of the data sent form the client. The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
I need to be notified when the image is sent, so that I can refresh the main view of the app with the new posts, including the recently posted by the client. In the practice if I request the backend for the last posts and the multipart hasn't finished, the sending of the image gets interruped and fails to send the image.
The backend is develop in WCF and is a RESTful JSON web service.
Here is the method that sends the post to the backend:
+(void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location;
{
NSLog(#"entro a addPost");
NSString *urlBackend = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"URLBackend"];
NSData* dataImage = UIImageJPEGRepresentation(image, 1.0);
NSString* ImageName = [NSString stringWithFormat:#"%#_%#.jpg",idUser ,dateToServer];
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#newPost",urlBackend]];
NSMutableURLRequest *request = [ [NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:requestData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend]
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
}
A couple of thoughts:
You say:
The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
Technically, you're not waiting for the information to be sent, but you're doing these concurrently. Do you want these to be concurrent? Or sequential? Or why not just a single request that posts the information as well as the image?
I'd suggest using AFNetworking for both requests. You've got a powerful framework for managing network requests, and it feels awkward to see hairy NSURLConnection code in there.
If you keep the NSURLConnection code in there, note that you do not want to start a NSURLConnection, unless you used initWithRequest:delegate:startImmediately: with NO for that last parameter. You're effectively starting it twice, which can cause problems. I'd suggest removing the start call.
Setting all of that aside, what you want to do is to add a completion block parameter to your method, e.g., something like:
+ (void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location completion:(void (^)(id responseObject, NSError *error))completion
{
// ...
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completion) completion(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completion) completion(nil, error);
}];
}
}
You'd then invoke that like so:
[Persistence addPostToServerAddtext:text addimage:image addbeach:nil location:annotation completion:^(id responseObject, NSError *error) {
if (error) {
// handle error
return
}
// otherwise use the responseObject
}];
Now, I don't know what parameters you want to return in your completion block (I'm assuming you wanted to return what the AFHTTPRequestOperationManager did), but just change the parameters for that completion block as suits your needs.
Unrelated to your original question, but I notice that you're building jsonRequest like so:
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
That's a little risky if any of those fields include user supplied information (e.g. what if the user used double quotes in the information provided). I'd suggest you build a dictionary, and then build the jsonRequest from that. It will be more robust. Thus:
NSDictionary *dictionary = #{#"Date" : date,
#"Message" : message};
NSError *error = nil;
NSData *request = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
if (error)
NSLog(#"%s: dataWithJSONObject error: %#", __FUNCTION__, error);
Or, if you use AFNetworking, I believe it will do this JSON conversion of your dictionary for you. But, bottom line, be very wary about creating JSON strings yourself, at least if the request might include any user supplied information.

Resources