2
votes

I've built an API client for communicating with my web-server and all HTTP requests in my app are done using this class: (subclass of AFHTTPRequestOperationManager)

    + (SNPAPIClient *)sharedClient {
          static SNPAPIClient *_sharedClient = nil;
          static dispatch_once_t onceToken;
           dispatch_once(&onceToken, ^{
               NSURL *baseURL = [NSURL URLWithString:BASE_URL];

                _sharedClient = [[SNPAPIClient alloc] initWithBaseURL:baseURL];
                _sharedClient.responseSerializer = [AFJSONResponseSerializer serializer];
                _sharedClient.requestSerializer = [AFJSONRequestSerializer serializer];

            });


      return _sharedClient;
 }

The class has 3 methods for POST, GET & POST-MULTIPART. While POST & GET methods work perfectly, I'm having issues with POST-MULTIPART.

    -(void)httpPOSTMultiPartRequestWithPath:(NSString*)path Parameters:(NSDictionary*)parameters BodyBlock:(id)bodyBlock Completion:(APICompletionBlock)apiComp{
comp = apiComp;
                            [self POST:path
                            parameters:parameters
             constructingBodyWithBlock:bodyBlock
                               success:^(NSURLSessionDataTask *task, id responseObject) {
                                    comp(responseObject,nil);
                                    }
                               failure:^(NSURLSessionDataTask *task, NSError *error) {
                                    comp(nil,error);
                                }];
  }

Specifically, I'm trying to send a simple JSON to the server followed by an image. I've tried doing something like this:

From my controller i'm calling:

NSDictionary *POSTpic = [NSDictionary dictionaryWithObjectsAndKeys:@"109",@"userId",@"P",@"contentType", nil];    

NSURL *pictuePath = [NSURL fileURLWithPath:@"cat.JPG"];

[[SNPAPIClient sharedClient]httpPOSTMultiPartRequestWithPath:@"PATH_GOES_HERE"
                                                  Parameters:POSTpic
                                                   BodyBlock:^(id<AFMultipartFormData> formData) {
                                                       [formData appendPartWithFileURL:pictuePath name:@"profile" error:nil];
                                                   }
                                                  Completion:^(id serverResponse, NSError *error){
                                                      if (serverResponse){
                                                          NSLog(@"success");
                                                      }else{
                                                          NSLog(@"error: %@",error);
                                                      }
                                                  }];

Sending this request I get the following error in debugger:

    internal server error (500)" UserInfo=0xb681650 {NSErrorFailingURLKey=http://"my_path",      AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0xb347d40> { URL: http://"my_path"   }         { status code: 500, headers {
         "Content-Length" = 142;
         "Content-Type" = "text/plain";
          Date = "Wed, 06 Nov 2013 19:26:05 GMT";
         "Proxy-Connection" = "Keep-alive";
          Server = "nginx admin";
      } }, NSLocalizedDescription=Request failed: internal server error (500)}

For some reason, even though I send an NSDictionary and my request serilaizer is set to AFJSONRequestSerializer, the JSON object is not created. Again, this only happens with POST MULTIPART, other requests done with the same client and settings, are processed correctly.

Thanks!

3

3 Answers

1
votes

The server is sending back a response with status code 500, which means that your server encountered an error while attempting to process the request. There doesn't appear to be anything wrong with how you're using AFNetworking, but the only way to tell is to debug things on the server side first.

1
votes

It has been a while since I solved this but maybe this could still help someone. Eventually, in my case, the upper level httpPOSTMultiPartRequestWithPath method did not cut and I needed more flexibility in the message structure (for instance, setting custom boundaries). I ended up using the HTTPRequestOperationWithRequest method and created the URLrequest manually.

-(void)httpPOSTmultipartContentWithPath:(NSString*)path Parameters:(NSDictionary*)parameters Body:(NSData*)body Completion:(APICompletionBlock)apiComp{

    NSURL *pathURL = [NSURL URLWithString:path];
    NSURLRequest *request = [self POSTRequestWithURL:pathURL DataDictionary:parameters andBody:body];

    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request
                                                                      success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                                          apiComp(responseObject,nil);
                                                                      } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                          apiComp(nil,error);
                                                                      }];

    [operation start];
}

- (NSMutableURLRequest *)POSTRequestWithURL:(NSURL *)url DataDictionary:(NSDictionary *)dictionary andBody:(NSData*)body
{

    // Create a POST request
    NSMutableURLRequest *myMedRequest = [NSMutableURLRequest requestWithURL:url];
    [myMedRequest setHTTPMethod:@"POST"];

    // Add HTTP header info

    NSString *boundary = @"*****";
    NSString *lineEnd = @"\r\n";
    NSString *twoHyphens = @"--";
    [myMedRequest addValue:[NSString stringWithFormat:@"multipart/form-data;boundary= %@", boundary] forHTTPHeaderField:@"Content-Type"];

    //create HTTP Body
    NSMutableData *POSTBody = [NSMutableData data];
    [POSTBody appendData:[[NSString stringWithFormat:@"boundary=%@%@%@",twoHyphens,boundary,lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"Content-Type:multipart/related;type=application/json;boundary=%@%@%@%@",twoHyphens,twoHyphens,boundary,lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"Content-Id:jsonTemp%@",lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"json\"%@%@", lineEnd,lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    //add JSON dictionary with request inforamtion
    [POSTBody appendData:[[NSString stringWithFormat:@"%@%@",dictionary
     ,lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];

    [POSTBody appendData:[lineEnd dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"%@%@%@",twoHyphens,boundary,lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"Content-Type:image/jpg"] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"%@",lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"Content-Id:%@",@"profile.jpg"] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"%@",lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"%@",lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];

    // Add image data
    [POSTBody appendData:body];


    // Add the closing -- to the POST Form
    [POSTBody appendData:[[NSString stringWithFormat:@"%@",lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];
    [POSTBody appendData:[[NSString stringWithFormat:@"%@%@%@%@",twoHyphens,boundary,twoHyphens, lineEnd] dataUsingEncoding:NSUTF8StringEncoding]];


    // Add the body to the myMedRequest & return
    [myMedRequest setHTTPBody:POSTBody];
    return myMedRequest;
}
0
votes

I encountered something similar on Rails 3.1 and upgrading to 3.2 solved it for me.