2014-06-16 16 views
54

Quindi questo codice HTML invia i dati nel formato corretto per me.POST multipart/form-data con Objective-C

<form action="https://www.example.com/register.php" method="post" enctype="multipart/form-data"> 
    Name: <input type="text" name="userName"><BR /> 
    Email: <input type="text" name="userEmail"><BR /> 
    Password: <input type="text" name="userPassword"><BR /> 
    Avatar: <input type="file" name="avatar"><BR /> 
    <input type="submit"> 
</form> 

Ho guardato in un buon numero di articoli su come fare un post multipart/form-data su iOS, ma nessuno davvero spiegare cosa fare se ci fossero normali parametri così come il caricamento del file.

Potresti per favore aiutarmi con il codice per POST questo in Obj-C?

Grazie!

risposta

147

Il processo è il seguente:

  1. Creare dizionario con le userName, userEmail e userPassword parametri.

    NSDictionary *params = @{@"userName"  : @"rob", 
             @"userEmail" : @"[email protected]", 
             @"userPassword" : @"password"}; 
    
  2. Determinare il percorso per l'immagine:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"]; 
    
  3. creare la richiesta:

    NSString *boundary = [self generateBoundaryString]; 
    
    // configure the request 
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 
    [request setHTTPMethod:@"POST"]; 
    
    // set content type 
    
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; 
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"]; 
    
    // create body 
    
    NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params paths:@[path] fieldName:fieldName]; 
    
  4. questo è il metodo utilizzato in precedenza per costruire il corpo della richiesta:

    - (NSData *)createBodyWithBoundary:(NSString *)boundary 
             parameters:(NSDictionary *)parameters 
              paths:(NSArray *)paths 
             fieldName:(NSString *)fieldName { 
        NSMutableData *httpBody = [NSMutableData data]; 
    
        // add params (all params are strings) 
    
        [parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) { 
         [httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
         [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]]; 
         [httpBody appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]]; 
        }]; 
    
        // add image data 
    
        for (NSString *path in paths) { 
         NSString *filename = [path lastPathComponent]; 
         NSData *data  = [NSData dataWithContentsOfFile:path]; 
         NSString *mimetype = [self mimeTypeForPath:path]; 
    
         [httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
         [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]]; 
         [httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]]; 
         [httpBody appendData:data]; 
         [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 
        } 
    
        [httpBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    
        return httpBody; 
    } 
    
  5. È possibile che questo utilizza i seguenti metodi di utilità:

    @import MobileCoreServices; // only needed in iOS 
    
    - (NSString *)mimeTypeForPath:(NSString *)path { 
        // get a mime type for an extension using MobileCoreServices.framework 
    
        CFStringRef extension = (__bridge CFStringRef)[path pathExtension]; 
        CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL); 
        assert(UTI != NULL); 
    
        NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType)); 
        assert(mimetype != NULL); 
    
        CFRelease(UTI); 
    
        return mimetype; 
    } 
    
    - (NSString *)generateBoundaryString { 
        return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]]; 
    } 
    
  6. quindi inviare la richiesta. Ci sono molte, molte opzioni qui.

    Ad esempio, se si utilizza NSURLSession, è possibile creare NSURLSessionUploadTask:

    NSURLSession *session = [NSURLSession sharedSession]; // use sharedSession or create your own 
    
    NSURLSessionTask *task = [session uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
        if (error) { 
         NSLog(@"error = %@", error); 
         return; 
        } 
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
        NSLog(@"result = %@", result); 
    }]; 
    [task resume]; 
    

    Oppure si potrebbe creare un NSURLSessionDataTask:

    request.HTTPBody = httpBody; 
    
    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
        if (error) { 
         NSLog(@"error = %@", error); 
         return; 
        } 
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
        NSLog(@"result = %@", result); 
    }]; 
    [task resume]; 
    

    È possibile che questo presuppone che il server è solo tornando risposta di testo. È preferibile che il server restituisca JSON, nel qual caso verrà utilizzato lo NSJSONSerialization anziché il metodo NSStringinitWithData.

    Allo stesso modo, sto utilizzando le versioni di blocco di completamento di NSURLSession sopra, ma sentitevi liberi di utilizzare anche le interpretazioni basate sui delegati più ricchi. Ma questo sembra oltre lo scopo di questa domanda, quindi ti lascio questo.

Ma si spera che questo illustri l'idea.


Sarei negligente se non ho punto che, molto più facile di quanto sopra, è possibile utilizzare AFNetworking, ripetendo i punti 1 e 2, ma poi basta chiamare:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; 
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON; if web service returns JSON, remove this line 
NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 
    NSError *error; 
    if (![formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"avatar" fileName:[path lastPathComponent] mimeType:@"image/png" error:&error]) { 
     NSLog(@"error appending part: %@", error); 
    } 
} progress:nil success:^(NSURLSessionTask *task, id responseObject) { 
    NSLog(@"responseObject = %@", responseObject); 
} failure:^(NSURLSessionTask *task, NSError *error) { 
    NSLog(@"error = %@", error); 
}]; 

if (!task) { 
    NSLog(@"Creation of task failed."); 
} 
+1

noti che è possibile anche generare un UUID utilizzando NSUUID: 'NSString * boundary = [NSString stringWithFormat: @ "Boundary -% @", [[NSUUID UUID] UUIDString]];' – Olivier

+0

Sì, se si don Non è necessario supportare le versioni di iOS precedenti alla 6.0, questo è un ottimo modo per farlo. – Rob

+2

Questa è una risposta fantastica. Complimenti e grazie. –

1

Prova a utilizzare questo per dati video e di immagini con diversi tipi di mime.

NSDictionary *param; 

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 

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

NSData *fileData; 
if ([objDoc.url containsString:@".mp4"]) { 
    manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"application/json"]; 
    [serializer setValue:@"video/mp4" forHTTPHeaderField:@"Content-Type"]; 
    manager.requestSerializer = serializer; 
} 

// 2. Create an `NSMutableURLRequest`. 

NSLog(@"filename =%@",objDoc.url); 
request= [serializer multipartFormRequestWithMethod:@"POST" URLString:strUrl parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 

    if ([objDoc.url containsString:@".mp4"]) { 
     [formData appendPartWithFileData:fileData 
            name:@"File" 
           fileName:@"video.mp4" 
           mimeType:@"video/mp4"]; 

    }else{ 
     [formData appendPartWithFileData:fileData 
            name:@"File" 
           fileName:@"image.jpeg" 
           mimeType:@"image/jpeg"]; 
    } 

} error:nil]; 

// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created. 

self.objeDocument.isUploading = [NSNumber numberWithInt:1]; 

self.operation = [manager HTTPRequestOperationWithRequest:request 
                success:^(AFHTTPRequestOperation *operation, id responseObject) { 

                 NSLog(@"Success %@", responseObject); 
                } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
                 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error!" message:@"The document attached has failed to upload." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
                 [alert show]; 
                 [self.operation cancel]; 
                 NSLog(@"Failure %@", error.description); 
                }]; 


// 4. Set the progress block of the operation. 
[self.operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten, 
             long long totalBytesWritten, 
             long long totalBytesExpectedToWrite) { 
    NSLog(@"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite); 
    float progress = (float)totalBytesWritten/(float)totalBytesExpectedToWrite; 


}]; 

// 5. Begin! 
[self.operation start]; 
1

POST immagini multiple utilizzando-dati del modulo a più parti o con Objective-C

-(void)multipleimageandstring 
{ 
    NSString *[email protected]"URL NAME"; 

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ; 
    [request setURL:[NSURL URLWithString:urlString]]; 
    [request setHTTPMethod:@"POST"]; 

    NSMutableData *body = [NSMutableData data]; 

    NSString *boundary = @"---------------------------14737809831466499882746641449"; 
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; 
    [request addValue:contentType forHTTPHeaderField:@"Content-Type"]; 

    // file 
    float low_bound = 0; 
    float high_bound =5000; 
    float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);//image1 
    int intRndValue = (int)(rndValue + 0.5); 
    NSString *str_image1 = [@(intRndValue) stringValue]; 

    UIImage *chosenImage1=[UIImage imageNamed:@"Purchase_GUI_curves-12 copy.png"]; 

    NSData *imageData = UIImageJPEGRepresentation(chosenImage1, 90); 
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"files\"; filename=\"%@.png\"\r\n",str_image1] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[NSData dataWithData:imageData]]; 
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 





    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"name\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[@"Nilesh" dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 

    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"apipassword\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithString:app.password] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 

    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"adminId\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[[NSString stringWithString:app.adminId] dataUsingEncoding:NSUTF8StringEncoding]]; 
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 

    // close form 
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    // set request body 
    [request setHTTPBody:body]; 

    //return and test 
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 
    NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; 

    NSLog(@"%@", returnString); 

} 
0

ho lottato con questo per un po ', se siete alla ricerca di caricamento di più immagini o altri tipi di file, può fare il seguente utilizzando AFNetworking 3.0

NSDictionary *params = @{key  : value, 
          ..... etc 
         }; 

NSString *urlString = @"http://..... your endpoint url"; 

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; 
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON; 

NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 
    for (int x = 0 ; x< contentArray.count; x++) { 
     AttachmentsModel *model = contentArray[x]; 

     if(model.type == ImageAttachmentType){ 
      [formData appendPartWithFileData:model.data name:model.name fileName:model.fileName mimeType:model.mimeType]; 

     }else if(model.type == AudioAttachmentType){ 
      NSURL *urlVideoFile = [NSURL fileURLWithPath:model.path]; 
      [formData appendPartWithFileURL:urlVideoFile name:model.name fileName:model.fileName mimeType:model.mimeType error:nil]; 
     }else{ 
      [formData appendPartWithFileURL:model.url name:model.name fileName:model.fileName mimeType:model.mimeType error:nil]; 

     } 

    } 
} progress:nil success:^(NSURLSessionTask *task, id responseObject) { 
    [Utility stopLoading]; 

    NSString *result = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]; 
    NSLog(@"result = %@", result); 

    id json = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil]; 


    if (block) { 

     //your response comes here 
    } 

} failure:^(NSURLSessionTask *task, NSError *error) { 
    NSLog(@"error = %@", error); 

}]; 

if (!task) { 
    NSLog(@"Creation of task failed."); 
} 

Ed ecco come la mia AttachmentsModel assomiglia:

// AttachmentsModel.h 

typedef enum AttachmnetType{ 
    ImageAttachmentType, 
    AudioAttachmentType, 
    VideoAttachmentType 
} AttachmnetType; 

@interface AttachmentsModel : NSObject 

@property (strong, nonatomic) NSString *path; 
@property (strong, nonatomic) NSData *data; 
@property (strong, nonatomic) NSString *mimeType; 
@property (strong, nonatomic) NSString *name; 
@property (strong, nonatomic) NSString *fileName; 
@property (strong, nonatomic) NSURL *url;