5

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

<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 构建表单数据只字未提,这里就是这种情况。

4

3 回答 3

14

好吧,在AFNetworking 3.0中,您可以像这样上传多格式零件数据,检查这个

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];
于 2016-01-22T04:37:16.093 回答
2

关于多部分的AFNetworking文档,声明您应该使用:

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

然后使用NSURLSessionUploadTaskforresume方法(链接中的完整代码)。

我无法让它与我正在使用的服务器一起使用,而是使用了 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
                               }];
于 2016-04-27T10:14:19.330 回答
1

如果你有一个大文件,你永远不想这样做,因为它需要将整个文件加载到内存中。这是一种将文件从磁盘流式传输到 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];
于 2017-03-16T19:17:19.207 回答