AFNetworking 使用 NSMutableURLRequest 上传?

Posted

技术标签:

【中文标题】AFNetworking 使用 NSMutableURLRequest 上传?【英文标题】:AFNetworking Upload Using NSMutableURLRequest? 【发布时间】:2014-03-31 13:03:17 【问题描述】:

我正在努力学习 AFNetworking,我从他们的 Github 中获取了样本。我不知道使用phpdataToPost 中设置哪些参数。我是Objective-Cphp 的新手。有人可以看看我的 sn-p 和我的php 看看我缺少什么。很难找到 AFNetworking 的“上传”教程,但那里有大量的 JSON 教程。

我想使用NSMutableURLRequest,因为最终我想从数组或UITableview 上传;到目前为止,这里是 mt 代码:

PHP:

<?php 
header("Content-Type: application/json");

$uploaddir = './';      //Uploading to same directory as PHP file
$file = basename($_FILES['userfile']['name']);
$uploadFile = $file;
$randomNumber = rand(0, 99999); 
$newName = $uploadDir . $randomNumber . $uploadFile;


if (!is_uploaded_file($_FILES['userfile']['tmp_name']))  
     $result = array("success" => false);  
      echo json_encode($result);  
      exit();


if ($_FILES['userfile']['size']> 300000) 
    $result = array("success" => false, "message" =>"the uploaded file is too big");  
          echo json_encode($result);  
          exit(); 


if (move_uploaded_file($_FILES['userfile']['tmp_name'], $newName)) 
    $postsize = ini_get('post_max_size');   //Not necessary, I was using these
    $canupload = ini_get('file_uploads');    //server variables to see what was 
    $tempdir = ini_get('upload_tmp_dir');   //going wrong.
    $maxsize = ini_get('upload_max_filesize');
    //echo "http://localhost:8888/upload/$file" . "\r\n" . $_FILES['userfile']['size'] . "\r\n" . $_FILES['userfile']['type'] ;
    $result = array("success"   => true,
                "code"      => 0,
                "message"   => "success",
                "postsize"  => $postsize,
                "canupload" => $canupload,
                "tempdir"   => $tempdir,
                "maxsize"   => $maxsize);
    echo json_encode($result);

?>

Xcode:

// 1. Create AFHTTPRequestSerializer which will create your request.
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];

// 2. Create an NSMutableURLRequest.
NSMutableURLRequest *request =
[serializer multipartFormRequestWithMethod:@"POST" URLString:@"http://my.com/upload/upload.php"
                                parameters:nil
                 constructingBodyWithBlock:^(id<AFMultipartFormData> formData) 
                     [formData appendPartWithFileData:imageData
                                                 name:@"userfile"
                                             fileName:@"myimage.jpg"
                                             mimeType:@"image/jpeg"];
                 ];

// 3. Create and use AFHTTPRequestOperationManager to create an AFHTTPRequestOperation from the NSMutableURLRequest that we just created.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *operation =
[manager HTTPRequestOperationWithRequest:request
                                 success:^(AFHTTPRequestOperation *operation, id responseObject) 
                                     NSLog(@"Success %@", responseObject);
                                  failure:^(AFHTTPRequestOperation *operation, NSError *error) 
                                     NSLog(@"Failure %@", error.description);
                                 ];

// 4. Set the progress block of the operation.
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
                                    NSInteger totalBytesWritten,
                                    NSInteger totalBytesExpectedToWrite) 
    NSLog(@"Wrote %ld/%ld", (long)totalBytesWritten, (long)totalBytesExpectedToWrite);
];

// 5. Begin!
[operation start];

错误(已解决):

2014-03-31 15:37:46.921 TestingUpload[7190:60b] Wrote 32768/59063
2014-03-31 15:37:46.922 TestingUpload[7190:60b] Wrote 59063/59063
2014-03-31 15:37:46.923 TestingUpload[7190:60b] Wrote 32768/59063
2014-03-31 15:37:46.923 TestingUpload[7190:60b] Wrote 59063/59063
2014-03-31 15:37:46.925 TestingUpload[7190:60b]     Success 
    canupload = 1;
    code = 0;
    maxsize = 32M;
    message = success;
    postsize = 32M;
    success = 1;
    tempdir = "/Applications/MAMP/tmp/php";

2014-03-31 15:37:46.927 TestingUpload[7190:60b]     Success 
    canupload = 1;
    code = 0;
    maxsize = 32M;
    message = success;
    postsize = 32M;
    success = 1;
    tempdir = "/Applications/MAMP/tmp/php";

感谢您的帮助和解释。谢谢!

【问题讨论】:

我没有测试过,但是随便看了一下,PHP看起来还不错。 检查上面。我不再关心太大了,因为它总是与设备大小相同。 如果您想小心一些恶意用户注意到文件上传的 URL 并决定将 2 GB 的文件上传到您的服务器上,那么太大的检查很重要。这就是为什么它通常在那里;以尽量减少被一些不法之徒滥用的机会。在您的测试中没什么大不了的,但在您投入生产之前,请考虑重新添加该代码(但使用 JSON 响应)。 是的,效果很好...我添加了一个 for 循环,看看我是否可以上传 2 张以上的图片,效果很好。你在说什么文件大小? @Rob 将 PHP 更新为我对 JSON/size 错误的解释。看起来怎么样? 【参考方案1】:

您的 PHP 正在寻找字段名称 userfile,但您的 Objective-C 正在使用 attachment。您必须在两个平台上使用相同的字段名称。我还假设“&lt;$php”只是一个错字,而您的本意是“&lt;?php”。

您可能需要考虑的其他一些改进:

    我建议您可能希望更改您的 PHP 以返回 JSON,而不仅仅是编写文本字符串。您的 Objective-C 代码将更容易解析响应并区分各种错误和成功。

    例如,如果成功,您的 PHP 可能会执行以下操作:

    $result = array("success" => true, "code" => 0, "message" => "success");
    

    或者,如果您想记录这些附加值,就像在现有代码示例中一样,您可以:

    $result = array("success"   => true,
                    "code"      => 0,
                    "message"   => "success",
                    "postsize"  => $postsize,
                    "canupload" => $canupload,
                    "tempdir"   => $tempdir,
                    "maxsize"   => $maxsize);
    

    如果不成功,你可以这样做:

    $result = array("success" => false, "code" => 1, "message" => "file not found");
    

    $result = array("success" => false, "code" => 2, "message" => "file too large");
    

    无论选择哪个$result,完成后,您都应该对其进行JSON编码并echo它(而不是回显简单的文本字符串):

    echo json_encode($result);
    

    显然,使用您想要的任何代码和消息,但想法是返回 JSON,它可以很容易地解析以确定上传请求是否成功,如果不成功,那么为什么。尝试解析来自服务器的简单文本响应本质上是脆弱的。

    无论如何,您的 Objective-C 可以解析此响应并检查 successcode 值并适当地处理这些场景。

    我不建议让 PHP 将上传文件保存在与 PHP 本身相同的文件夹中。至少,我会为上传创建一个专用子目录。我个人会选择一个完全在 Web 服务器目录结构之外的目录。

【讨论】:

感谢您回复我。我在parameters:dataToPost 中传递了什么? 谢谢!我正在考虑使用nil,但不想贸然下结论。如果我在查询 mysql 并且需要 URL 中的“用户名”和“密码”,是否使用参数?我需要将attachment 更改为userFileformdata 中的 fileName 怎么样?这有关系吗?它只是一个占位符吧? Xcode 说multipartFormRequestWithMethod 被贬值了? 我用错误和固定代码编辑了我的问题。【参考方案2】:

根据您更新的代码示例和报告的警告/错误,我有一些观察:

    您收到关于 multipartFormRequestWithMethod 被弃用的消息,因为您使用的是不带 error 参数的演绎版,但它已被另一个带有此附加参数的演绎版替换。有关详细信息,请参阅AFURLRequestSerialization.h 中此方法的声明。

    您关于text/html 的错误是由于PHP 发送的响应的标题报告Content-typetext/html。如果您的 PHP 脚本没有在您的 PHP 中发送回 JSON,您必须更改您的 Objective-C 代码,以便它知道期待一个 HTTP 响应(默认情况下,它期待返回 JSON):

    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    

    这告诉AFHTTPRequestOperationManager 接受来自服务器的任何 HTTP 响应。

    或者,如果您将 PHP 更改为返回 JSON(恕我直言,您应该这样做),您不仅需要将 PHP 代码更改为结果的 echojson_encode,还需要通知 PHP 指定适当的Content-Type 在标题中。因此,在您 echo PHP 中的任何 JSON 之前),将以下行添加到 PHP 代码中:

    header("Content-Type: application/json");
    

    你说:

    我以为内容类型是在mimetype中定义的

    mimetype 为多部分请求的该部分定义了Content-type。但是整个请求也有自己的Content-type 标头。该响应还在其标题中包含Content-type 设置。此错误告诉您响应包含text/htmlContent-type,它预期application/json。 (请参阅我之前关于修复该问题的观点。)

【讨论】:

好的,谢谢。同时,我将研究AFURLRequestSerialization.h,并在我的答案中更新了 PHP。

以上是关于AFNetworking 使用 NSMutableURLRequest 上传?的主要内容,如果未能解决你的问题,请参考以下文章

将 NSMutable 数组存储到 sqlite 数据库中

NsMutable 不是 swift 中 [anyobject] 的子类型

如何将 NSString 值设置为 NSMutable 字典?

NSUserDefaults NSMutable 数组未在会话之间保存

将对象添加到排序的 NSMutable 数组并回答索引路径

如何将 NSMutable 数组中的数据存储在 Core Data 中?