Загрузите изображение с помощью AFNetworking 2.0

Я не могу понять, почему это так сложно. Все учебники и статьи в Интернете, похоже, говорят об 1,0 api, что довольно бесполезно.

Я пробовал несколько разных способов и получал разные результаты. Что я делаю неправильно?

  • задача загрузки - похоже, не используется многочастная форма, wtf?

    NSMutableURLRequest *request = [self.manager.requestSerializer multipartFormRequestWithMethod:@"POST"
                                                                                      URLString:[[NSURL URLWithString:url relativeToURL:[NSURL URLWithString:ApiBaseUrl]] absoluteString]
                                                                                     parameters:@{}
                                                                      constructingBodyWithBlock:nil];
    
    NSProgress *progress;
    NSURLSessionUploadTask *task = [self.manager uploadTaskWithRequest:request
                                                            fromData:data
                                                            progress:&progress
                                                   completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
                                                     if (error) {
                                                       NSLog(@"[error description] = %@", [error description]);
                                                     } else {
                                                       NSLog(@"success!");
                                                     }
                                                   }];
    
    [task resume];
    
  • сообщение с блоком - это, кажется, не придает ничего

    [self.manager POST:url
               parameters:@{}
    constructingBodyWithBlock:^(id <AFMultipartFormData> formData) {
        [formData appendPartWithFileData:data
                                    name:@"post[picture]"
                                fileName:@"picture.jpg"
                                mimeType:@"image/jpeg"];
    }
                  success:^(NSURLSessionDataTask *task, id response) {
                    NSLog(@"Success");
                  }
                  failure:^(NSURLSessionDataTask *task, NSError *error) {
                    NSLog(@"Error: %@", error);
                  }];
    
  • простая запись - кажется, почти работает... но не

    [self.manager POST:url
            parameters:@{@"post[picture][]":data}
               success:^(NSURLSessionDataTask *task, id response) {
                 NSLog(@"Success");
               }
               failure:^(NSURLSessionDataTask *task, NSError *error) {
                 NSLog(@"Error: %@", error);
               }];
    

Мне бы очень понравилось работать, но я не уверен, почему это не так.

Ответ 1

Для правильно сформированного тела "multipart/form-data" вам нужно использовать блок построения тела при создании запроса. В противном случае задача загрузки использует исходные данные как тело. Например, в подклассе AFHTTPSessionManager:

NSString *urlString = [[NSURL URLWithString:kPhotoUploadPath relativeToURL:self.baseURL] absoluteString];
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:urlString parameters:params constructingBodyWithBlock:^(id <AFMultipartFormData> formData) {
    [formData appendPartWithFileData:photo.data name:@"photo" fileName:@"photo.jpg" mimeType:@"image/jpeg"];
}];

NSURLSessionUploadTask *task = [self uploadTaskWithStreamedRequest:request progress:progress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
    if (error) {
        if (failure) failure(error);
    } else {
        if (success) success(responseObject);
    }
}];
[task resume];

Или, если вам не нужно отслеживать процесс загрузки, вы можете просто использовать:

[self POST:kPhotoUploadPath parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    [formData appendPartWithFileData:photo.data name:@"photo" fileName:@"photo.jpg" mimeType:@"image/jpeg"];
} success:^(NSURLSessionDataTask *task, id responseObject) {
    if (success) success(responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    if (failure) failure(error);
}];

Ответ 2

То, что описывает Ray Lillywhite, прекрасно работает (я бы сделал комментарий к его сообщению, но моя репутация слишком низкая).

  • Получить правильную версию AFNetworking, содержащую это исправление для обновления прогресса при использовании многопользовательских запросов. На момент написания этой версии это HEAD.
  • Создайте NSMutableURLRequest с помощью multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error:.
    • Создайте данные формы с помощью одного из методов appendPartWith....
  • Получить (загрузить) задачу данных, вызвав правильный метод uploadTaskWith.... Вам нужно использовать uploadTaskWithStreamedRequest:progress:completionHandler:, если вы хотите использовать входной параметр NSProgress.