iOS — AFNETWORKING 2.0 — AFHTTPRequestOperationManager — POST-MULTIPART-REQUEST

Я создал клиент API для связи с моим веб-сервером, и все HTTP-запросы в моем приложении выполняются с использованием этого класса: (подкласс 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;
 }

Класс имеет 3 метода для POST, GET и POST-MULTIPART. Хотя методы POST и GET работают отлично, у меня возникают проблемы с 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);
                                }];
  }

В частности, я пытаюсь отправить на сервер простой JSON, за которым следует изображение. Я пытался сделать что-то вроде этого:

С моего контроллера я звоню:

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);
                                                      }
                                                  }];

Отправляя этот запрос, я получаю следующую ошибку в отладчике:

    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)}

По какой-то причине, несмотря на то, что я отправляю NSDictionary, а для моего запроса Serilaizer установлено значение AFJSONRequestSerializer, объект JSON не создается. Опять же, это происходит только с POST MULTIPART, другие запросы, сделанные с тем же клиентом и настройками, обрабатываются правильно.

Спасибо!


person Matan Guttman    schedule 04.11.2013    source источник


Ответы (3)


Сервер отправляет ответ с кодом состояния 500, что означает, что ваш сервер обнаружил ошибка при попытке обработать запрос. Кажется, нет ничего плохого в том, как вы используете AFNetworking, но единственный способ узнать это — сначала отладить вещи на стороне сервера.

person mattt    schedule 17.11.2013

Прошло некоторое время с тех пор, как я решил это, но, возможно, это все еще может помочь кому-то. В конце концов, в моем случае метод httpPOSTMultiPartRequestWithPath верхнего уровня не работал, и мне потребовалась большая гибкость в структуре сообщения (например, установка пользовательских границ). В итоге я использовал метод HTTPRequestOperationWithRequest и вручную создал URL-запрос.

-(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;
}
person Matan Guttman    schedule 27.12.2013

Я столкнулся с чем-то похожим на Rails 3.1, и обновление до 3.2 решило это для меня.

person shaioz    schedule 09.03.2014