objective-c http-post http-post-vars

objective c - POST multipart/form-data con Objective-C



http-post http-post-vars (4)

Entonces este código HTML envía los datos en el formato correcto para mí.

<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>

He analizado una buena cantidad de artículos sobre cómo hacer un POST multipart / form-data en iOS, pero ninguno realmente explica qué hacer si hubiera parámetros normales además de la carga del archivo.

¿Podría ayudarme con el código para PUBLICAR esto en Obj-C?

¡Gracias!


El proceso es el siguiente:

  1. Crear diccionario con los parámetros userName , userEmail y userPassword .

    NSDictionary *params = @{@"userName" : @"rob", @"userEmail" : @"[email protected]", @"userPassword" : @"password"};

  2. Determine la ruta de la imagen:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];

  3. Crea la solicitud:

    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. Este es el método utilizado anteriormente para construir el cuerpo de la solicitud:

    - (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. Lo anterior usa los siguientes métodos de utilidad:

    @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. Luego envíe la solicitud. Hay muchas, muchas opciones aquí.

    Por ejemplo, si usa NSURLSession , puede crear 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];

    O puede crear una 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];

    Lo anterior supone que el servidor solo está devolviendo respuesta de texto. Es mejor si el servidor devolvió JSON, en cuyo caso utilizaría NSJSONSerialization lugar del método initWithData .

    Del mismo modo, estoy usando las representaciones de bloque de finalización de NSURLSession anterior, pero también puede utilizar las versiones más ricas basadas en delegados. Pero eso parece estar fuera del alcance de esta pregunta, así que te lo dejo.

Pero espero que esto ilustre la idea.

Sería negligente si no AFNetworking que, mucho más fácil que lo anterior, puede usar AFNetworking , repitiendo los pasos 1 y 2 anteriores, pero luego simplemente llamando:

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."); }


Intenta usar esto para los datos de video y de imagen con diferentes tipos de 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];


PUBLICAR múltiples imágenes usando multiparte o datos de formulario con Objective-C

-(void)multipleimageandstring { NSString *urlString=@"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); }


Tuve problemas con esto por un tiempo, si está buscando cargar varias imágenes o cualquier otro tipo de archivo, puede hacer lo siguiente usando 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."); }

Y así es como se ve mi AttachmentsModel:

// 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;