【问题标题】:AFNetworking 3.x multipart form uploadAFNetworking 3.x 多部分表单上传
【发布时间】:2016-04-28 13:17:22
【问题描述】:

我有一个这样的上传表单:

<form action="http://localhost/upload.php" method="post" enctype="multipart/form-data">
    <input type="file" id="upload" name="upload" />
</form>

和php代码继续上传表单:

isset($_FILES["upload"]) or die("Error");
// Path prepare stuff
if (move_uploaded_file($_FILES["upload"]["tmp_name"], $outputFile)) {
    // Other processing stuffs
}

在 xcode 中,我像这样构造请求:

NSMutableURLRequest* request = [[AFHTTPRequestSerializer serializer]
                                multipartFormRequestWithMethod:@"POST"
                                URLString:@"http://localhost/upload.php"
                                parameters:nil
                              constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
                                    [formData appendPartWithFormData:data name:@"somefilename.ext"];
                                } error:nil];

但是好像我做错了,对吧?

更新

我是 AFNetworking 的新手,我想了解它如何像上面那样构建 multiplart/form-data 帖子。看起来代码缺少输入名称“上传”,因此将无法通过第一行 php 上传脚本。我从 AFNetworking 的 GitHub 上阅读了该文档,但他们没有提及使用 NSData 构建表单数据,这里就是这种情况。

【问题讨论】:

  • 你想使用afnetworking调用服务吗...?
  • @RamaniAshish 好吧,实际上它不是服务。只是一个用 php 编写的简单上传脚本,我只想知道如何请求该 php 脚本通过 AFNetworking 3.x 上传 NSData 对象而不是文件

标签: ios afnetworking-3


【解决方案1】:

嗯,在AFNetworking 3.0你可以这样做上传多格式零件数据,Check this

AFNetworking 3.0 是 AFNetworking 的最新主要版本,3.0 删除了对现已弃用的基于 NSURLConnection 的 API 的所有支持。如果您的项目以前使用这些 API,建议您现在升级到基于 NSURLSession 的 API。本指南将引导您完成该过程。

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://localhost/upload.php" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

   [formData appendPartWithFileData:data name:@"uploadFile" fileName:@"somefilename.txt" mimeType:@"text/plain"] // you file to upload

} error:nil];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

NSURLSessionUploadTask *uploadTask;
uploadTask = [manager
          uploadTaskWithStreamedRequest:request
          progress:^(NSProgress * _Nonnull uploadProgress) {
              // This is not called back on the main queue.
              // You are responsible for dispatching to the main queue for UI updates
              dispatch_async(dispatch_get_main_queue(), ^{
                  //Update the progress view
                  [progressView setProgress:uploadProgress.fractionCompleted];
              });
          }
          completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
              if (error) {
                  NSLog(@"Error: %@", error);
              } else {
                  NSLog(@"%@ %@", response, responseObject);
              }
          }];

[uploadTask resume];

【讨论】:

  • 我没有上传文件,而是使用 NSData 构造数据表单&这里是函数的签名:[formData appendPartWithFormData:&lt;#(nonnull NSData *)#&gt; name:&lt;#(nonnull NSString *)#&gt;]。这个函数不允许我传递输入的名称。
  • 在名称中你应该传递它的参数
  • @MayankPatel 你能检查一下我关于 afnetwoking 3.0 中文件上传的问题吗stackoverflow.com/questions/39325058/…
  • 除了文件流我们如何做到这一点?如果文件很大,您不希望将整个文件保存在内存中。
  • 你需要问后端人这是后端人的问题
【解决方案2】:

AFNetworking doc 关于多部分,声明您应该使用:

[[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"......

然后将NSURLSessionUploadTask 用于resume 方法(链接中的完整代码)。

我无法在我正在处理的 服务器 上使用此功能,而是使用了 AFHTTPSessionManager:

AFHTTPSessionManager *manager = [AFHTTPSessionManager alloc]initWithBaseURL: @"someURL..."];
// If you need to add few more headers, now is the time - if not you can skip this
[manager setRequestSerializer:[AFJSONRequestSerializer serializer]];
[[manager requestSerializer] setValue:@"your custom value"
                    forHTTPHeaderField:@"relevant key"];
// Setting basic auth - only if you need it
[[manager requestSerializer] setAuthorizationHeaderFieldWithUsername:@"username"
                                                             password:@"password"];


             [manager POST:@"appendedPath"
                parameters:params
 constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

                   [formData appendPartWithFileData:yourNSDataFile
                                               name:@"file"
                                           fileName:@"customFileName"
                                           // The server I was working on had no type but you can google for all the existing types
                                           mimeType:@""];

             }

                 progress:nil
                  success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

                                   if (responseObject != nil)
                                   {
                                       NSDictionary *jsonDictionary = responseObject;
                                   }
                               }

                   failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

                                     // Handle your error
                               }];

【讨论】:

    【解决方案3】:

    如果你有一个大文件,你永远不会想这样做,因为它需要将整个文件加载到内存中。这是一种将文件从磁盘流式传输到 HTTP 请求的方法,这样您的内存使用率就会保持在较低水平。感谢您的原始答案!它就像一个魅力。

    NSInputStream *fileInputStream = [[NSInputStream alloc] initWithFileAtPath:filePath];
    
    if (!fileInputStream) {
        NSLog(Error, @"Could not get a fileInputStream from the file path");
        return;
    }
    
    NSError *error;
    
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"PUT" URLString:fullUrlStr parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    
        [formData appendPartWithInputStream:fileInputStream name:@"uniqueIdentifier" fileName:@"filename" length:<lengthOfFileLong>];
    
    } error:&error];
    
    if (error) {
        NSLog(Error, @"Error creating multipart form upload request: %@", [error userInfo]);
        completionHandler(nil, error);
    }
    
    [request setAllHTTPHeaderFields:headerDictionary];
    
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
    NSURLSessionUploadTask *uploadTask;
    uploadTask = [manager
                  uploadTaskWithStreamedRequest:request
                  progress:^(NSProgress * _Nonnull uploadProgress) {
                      // This is not called back on the main queue.
                      // You are responsible for dispatching to the main queue for UI updates
    
                      NSLog(Debug, @"Cloud Upload Completion: %f", uploadProgress.fractionCompleted);
                  }
                  completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
    
                      if (error) {
                          NSLog(@"Error: %@", [error userInfo]);
                          completionHandler(nil, error);
                      } else {
                          NSLog(@"Success: %@ %@", response, responseObject);
                      }
                  }];
    
    [uploadTask resume];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-02
      • 1970-01-01
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多