POST jpeg upload with AFNetworking

2019-02-02 20:02发布

问题:

I can't for the life of me figure out why this doesn't work when I use AFNetworking. It worked with ASIHTTP. This is all very new to me. But I can't figure out why the files are not being transferred from $_FILES to the server's HD anymore. Here's the iOS code:

- (IBAction)uploadPressed 
{
[self.fileName resignFirstResponder];
NSURL *remoteUrl = [NSURL URLWithString:@"http://mysite.com"];

NSTimeInterval timeInterval = [NSDate timeIntervalSinceReferenceDate];
NSString *photoName=[NSString stringWithFormat:@"%lf-Photo.jpeg",timeInterval];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

// the path to write file
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:photoName];
NSData * photoImageData = UIImageJPEGRepresentation(self.remoteImage.image, 1.0);
[photoImageData writeToFile:filePath atomically:YES];

NSLog(@"photo written to path: e%@", filePath);

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:remoteUrl];
NSMutableURLRequest *afRequest = [httpClient multipartFormRequestWithMethod:@"POST" 
                                                                       path:@"/photos" 
                                                                 parameters:nil 
                                                  constructingBodyWithBlock:^(id <AFMultipartFormData>formData) 
                                  {
                                      [formData appendPartWithFormData:[self.fileName.text dataUsingEncoding:NSUTF8StringEncoding] 
                                                                  name:@"name"];


                                      [formData appendPartWithFileData:photoImageData 
                                                                  name:self.fileName.text 
                                                              fileName:filePath 
                                                              mimeType:@"image/jpeg"]; 
                                  }
                                  ];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
[operation setUploadProgressBlock:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {

    NSLog(@"Sent %d of %d bytes", totalBytesWritten, totalBytesExpectedToWrite);

}];

   [operation setCompletionBlock:^{
    NSLog(@"%@", operation.responseString); //Gives a very scary warning
}];

[operation start];    



}

I used to do this:

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:remoteUrl];
[request setPostValue:self.fileName.text forKey:@"name"];
[request setFile:filePath forKey:@"filename"];
[request setDelegate:self];
[request startAsynchronous];

Here's my PHP:

 {
// these could be stored in a .ini file and loaded
// via parse_ini_file()... however, this will suffice
// for an example
$codes = Array(
    100 => 'Continue',
    101 => 'Switching Protocols',
    200 => 'OK',
    201 => 'Created',
    202 => 'Accepted',
    203 => 'Non-Authoritative Information',
    204 => 'No Content',
    205 => 'Reset Content',
    206 => 'Partial Content',
    300 => 'Multiple Choices',
    301 => 'Moved Permanently',
    302 => 'Found',
    303 => 'See Other',
    304 => 'Not Modified',
    305 => 'Use Proxy',
    306 => '(Unused)',
    307 => 'Temporary Redirect',
    400 => 'Bad Request',
    401 => 'Unauthorized',
    402 => 'Payment Required',
    403 => 'Forbidden',
    404 => 'Not Found',
    405 => 'Method Not Allowed',
    406 => 'Not Acceptable',
    407 => 'Proxy Authentication Required',
    408 => 'Request Timeout',
    409 => 'Conflict',
    410 => 'Gone',
    411 => 'Length Required',
    412 => 'Precondition Failed',
    413 => 'Request Entity Too Large',
    414 => 'Request-URI Too Long',
    415 => 'Unsupported Media Type',
    416 => 'Requested Range Not Satisfiable',
    417 => 'Expectation Failed',
    500 => 'Internal Server Error',
    501 => 'Not Implemented',
    502 => 'Bad Gateway',
    503 => 'Service Unavailable',
    504 => 'Gateway Timeout',
    505 => 'HTTP Version Not Supported'
);

return (isset($codes[$status])) ? $codes[$status] : '';
}

function sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
$status_header = 'HTTP/1.1 ' . $status . ' ' . getStatusCodeMessage($status);
header($status_header);
header('Content-type: ' . $content_type);
echo $body;
}

if (!empty($_FILES) && isset($_POST["name"])) {
            $name = $_POST["name"];
            $tmp_name = $_FILES['filename']['tmp_name'];
            $uploads_dir = '/var/www/cnet/photos';
            move_uploaded_file($tmp_name, "$uploads_dir/$name.jpg");
            $result = array("SUCCEEDED");
            sendResponse(200, json_encode($result));
            } else {

            sendResponse(400, 'Nope');
            }
?>

回答1:

Try this snippet of code:

    NSData* sendData = [self.fileName.text dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *sendDictionary = [NSDictionary dictionaryWithObject:sendData forKey:@"name"];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:remoteUrl];
    NSMutableURLRequest *afRequest = [httpClient multipartFormRequestWithMethod:@"POST" 
                                                                           path:@"/photos" 
                                                                     parameters:sendDictionary 
                                                      constructingBodyWithBlock:^(id <AFMultipartFormData>formData) 
                                      {                                     
                                          [formData appendPartWithFileData:photoImageData 
                                                                      name:self.fileName.text 
                                                                  fileName:filePath 
                                                                  mimeType:@"image/jpeg"]; 
                                      }
                                      ];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
    [operation setUploadProgressBlock:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {

        NSLog(@"Sent %d of %d bytes", totalBytesWritten, totalBytesExpectedToWrite);

    }];

    [operation setCompletionBlock:^{
        NSLog(@"%@", operation.responseString); //Gives a very scary warning
    }];

    [operation start]; 


回答2:

I'm not really familiar with what ASI is doing with setPostValue:forKey:, but you may be missing a name parameter to be sent separately from the image upload.

What does either the client or server log, exactly? Is the progress block logging?

A few other points:

  • You can just do [operation start] at the end; no need to create an operation queue for just that.
  • To help with logging, set completionBlock on operation, with an NSLog of the response, or something like that.
  • You may want to create an AFHTTPClient base class with a class method to return a singleton instance, like the Gowalla API client in the AFNetworking example app. That client can then manage a single operation queue for all of your network requests.


回答3:

I've got a workaround using NSMutableURLRequest:

NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:remoteUrl];
[req setHTTPMethod:@"POST"];

NSString *contentType = [NSString stringWithFormat:@"multipart/form-data, boundary=%@", boundary];
[req setValue:contentType forHTTPHeaderField:@"Content-type"];

//adding the body:
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[@"Content-Disposition: form-data; name=\"name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[name dataUsingEncoding:NSUTF8StringEncoding]];

[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[@"Content-Disposition: form-data; name=\"filename\";\r\nfilename=\"china.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[NSData dataWithData:imageData]];
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[req setHTTPBody:postBody];