使用AFNetworking 2.0上传图片

10

我不明白为什么这很难。所有在线教程和文章似乎都在谈论1.0 API,而那个已经没用了。

我尝试了几种不同的方法,但得到了不同的结果。我做错了什么?

  1. 上传任务 - 这似乎没有使用多部分表单,什么鬼?

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

    我很想让它起作用,但我不确定为什么它没起作用。


    当您在第一步使用NSURLSessionUploadTask时,您从哪里获取数据?我正在做类似的事情(尽管不是多部分POST),首先构建请求,然后使用request.HTTPBody作为数据。 - Bart Vandendriessche
    你能解决这个问题吗?我也遇到了同样的问题。我需要在图片中发送参数,已经尝试了三种可能的方法,包括你提到的,但都没有起作用。Afnetworking也没有提供任何示例。 - YogiAR
    你解决了吗?我有类似的问题,你能帮我吗?https://dev59.com/833aa4cB1Zd3GeqPaDYe - Matrosov Oleksandr
    2个回答

    14

    对于一个正确构建的"multipart/form-data" body,您需要在创建请求时使用body construction block。否则上传任务将使用原始数据作为body。例如,在您的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);
    }];
    

    很抱歉,第一个答案是不正确的,因为uploadTaskWithStreamedRequest:是用于流式请求的,即通过持久的URL连接。 - jpsim
    我认为在这个上下文中,“streamed”并不是指流式传输的意思。它可能只是指它是一个多部分表单请求:http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 我的理解是请求正文是以流的形式传输的,但连接不是持久的,并且一旦请求完成就会关闭。这是上传文件的标准请求类型。“uploadTaskWithStreamedRequest:”也被AFNetworking的“...constructingBodyWithBlock:...”方法使用。 - Ray Lillywhite
    @RayLillywhite 但是当我检查我的photo.data时,它是nil的,你能看一下我的类似问题https://dev59.com/833aa4cB1Zd3GeqPaDYe吗? - Matrosov Oleksandr

    5

    Ray Lillywhite所描述的很好地发挥了作用(我本来想在他的帖子上发表评论,但我的声誉太低了)。

    1. 获取包含此修复程序以在使用多部分请求时更新进度的正确版本的AFNetworking。在撰写本文时,该版本为HEAD。
    2. 通过multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error:的帮助创建一个NSMutableURLRequest
      • 通过一个appendPartWith...方法来构建表单数据。
    3. 通过调用正确的uploadTaskWith...方法来获取(上传)数据任务。如果要使用NSProgress输入参数,则需要使用uploadTaskWithStreamedRequest:progress:completionHandler:

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接