NSData y carga de imágenes a través de POST en iOS

He estado revisando las muchas publicaciones sobre cómo subir imágenes a través de POST en iOS. A pesar de la gran cantidad de información sobre este tema, no puedo cargar correctamente los datos JPEG tomados de mi iPhone Simulator Photo Library. La información, una vez en el servidor, es solo una gran cadena de hexadecimal. ¿No debería NSData simplemente ser un flujo de bytes? No entiendo qué está pasando con todo el hexadecimal, o por qué este código parece funcionar para todos los demás.

Aquí está el código en cuestión:

-(void)uploadWithUserLocationString:(NSString*)userLocation{ NSString *urlString = @"http://some.url.com/post"; // set up the form keys and values (revise using 1 NSDictionary at some point - neater than 2 arrays) NSArray *keys = [[NSArray alloc] initWithObjects:@"auth",@"text",@"location",nil]; NSArray *vals = [[NSArray alloc] initWithObjects:self.authToken,self.textBox.text,userLocation,nil]; // set up the request object NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; [request setURL:[NSURL URLWithString:urlString]]; [request setHTTPMethod:@"POST"]; //Add content-type to Header. Need to use a string boundary for data uploading. NSString *boundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"]; NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; //create the post body NSMutableData *body = [NSMutableData data]; [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]]; //add (key,value) pairs (no idea why all the \r's and \n's are necessary ... but everyone seems to have them) for (int i=0; i<[keys count]; i++) { [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]]; [body appendData:[[NSString stringWithFormat:@"%@",[vals objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]]; [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]]; } [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"image\"\r\n"] dataUsingEncoding:NSASCIIStringEncoding]]; [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSASCIIStringEncoding]]; [body appendData:[NSData dataWithData:self.imageData]]; [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]]; // set the body of the post to the reqeust [request setHTTPBody:body]; // make the connection to the web NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSLog(returnString); [keys release]; [vals release]; } 

Gracias por tu tiempo.

Este código funciona en mi aplicación. Si no está utilizando ARC, deberá modificar el código para liberar todo lo que se haya asignado.

 // create request NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; [request setHTTPShouldHandleCookies:NO]; [request setTimeoutInterval:30]; [request setHTTPMethod:@"POST"]; // set Content-Type in HTTP header NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request setValue:contentType forHTTPHeaderField: @"Content-Type"]; // post body NSMutableData *body = [NSMutableData data]; // add params (all params are strings) for (NSString *param in _params) { [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"%@\r\n", [_params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]]; } // add image data NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0); if (imageData) { [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithString:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:imageData]; [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; } [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // setting the body of the post to the reqeust [request setHTTPBody:body]; // set URL [request setURL:requestURL]; 

Espero que este código ayude a otro cuerpo …

 //create request NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; //Set Params [request setHTTPShouldHandleCookies:NO]; [request setTimeoutInterval:60]; [request setHTTPMethod:@"POST"]; //Create boundary, it can be anything NSString *boundary = @"------VohpleBoundary4QuqLuM1cE5lMwCy"; // set Content-Type in HTTP header NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request setValue:contentType forHTTPHeaderField: @"Content-Type"]; // post body NSMutableData *body = [NSMutableData data]; //Populate a dictionary with all the regular values you would like to send. NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; [parameters setValue:param1 forKey:@"param1-name"]; [parameters setValue:param2 forKey:@"param2-name"]; [parameters setValue:param3 forKey:@"param3-name"]; // add params (all params are strings) for (NSString *param in parameters) { [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"%@\r\n", [parameters objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]]; } NSString *FileParamConstant = @"imageParamName"; NSData *imageData = UIImageJPEGRepresentation(imageObject, 1); //Assuming data is not nil we add this to the multipart form if (imageData) { [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Type:image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:imageData]; [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; } //Close off the request with the boundary [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // setting the body of the post to the request [request setHTTPBody:body]; // set URL [request setURL:[NSURL URLWithString:baseUrl]]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; if ([httpResponse statusCode] == 200) { NSLog(@"success"); } }]; 

Eche un vistazo al proyecto de ejemplo SimpleURLConnections de Apple. Puede usar PostController desde allí con algunas modificaciones.

Sin embargo, no es exactamente simple. La diferencia con la solución anterior es que Apple está usando una transmisión para transmitir el archivo al servidor. Eso es mucho más amigable con la memoria que mantener los datos codificados de imagen durante la carga. También es mucho más complicado.

 NSData *imgData = UIImagePNGRepresentation(imgUser.image); NSString *str=[NSString stringWithFormat:@"%@upload_image",appDelegate.strRoot]; NSString *urlString = [NSString stringWithFormat:@"%@",str]; 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"]; [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"a.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[NSData dataWithData:imgData]]; [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; // parameter UserId [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userid\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[appDelegate.strUserID dataUsingEncoding:NSUTF8StringEncoding]]; [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; // close form [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // setting the body of the post to the request [request setHTTPBody:body]; NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; // NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",dict); 

Veo que envía múltiples archivos en una sola solicitud, ¿correcto?

A partir de la especificación HTTP , debe usar multipart / mixed Content-type dentro de incrustación multipart / form-data

Ejemplo del enlace de arriba:

 Content-type: multipart/form-data, boundary=AaB03x --AaB03x content-disposition: form-data; name="field1" Joe Blow --AaB03x content-disposition: form-data; name="pics" Content-type: multipart/mixed, boundary=BbC04y --BbC04y Content-disposition: attachment; filename="file1.txt"