NSData и загрузка изображений через POST в iOS

#iphone #ios #post #nsdata #nsurlrequest

#iPhone #iOS #Публикация #nsdata #nsurlrequest

Вопрос:

Я просмотрел множество сообщений о загрузке изображений через POST в iOS. Несмотря на обилие информации по этой теме, мне не удается корректно загрузить данные в формате JPEG, взятые из моей фотобиблиотеки iPhone Simulator. Данные, попавшие на сервер, представляют собой просто огромную строку в шестнадцатеричном формате. Разве NSData не должна быть просто потоком байтов? Я не понимаю, что происходит со всеми шестнадцатеричными значениями или почему этот код, похоже, работает для всех остальных.

Вот код, о котором идет речь:

 -(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:@"--%@rn",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="%@"rnrn",[keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@",[vals objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"rn--%@rn",boundary] dataUsingEncoding:NSASCIIStringEncoding]];
}
[body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name="image"rn"] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[[NSString stringWithString:@"Content-Type: application/octet-streamrnrn"] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[NSData dataWithData:self.imageData]];
[body appendData:[[NSString stringWithFormat:@"rn--%@--rn",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];
}
  

Спасибо за ваше время.

Ответ №1:

Этот код работает в моем приложении. Если вы не используете ARC, вам нужно будет изменить код, чтобы освободить что-либо выделенное.

 // 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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"rnrn", param] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@rn", [_params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}

// add image data
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
if (imageData) {
    [body appendData:[[NSString stringWithFormat:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="image.jpg"rn", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Type: image/jpegrnrn"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:imageData];
    [body appendData:[[NSString stringWithFormat:@"rn"] dataUsingEncoding:NSUTF8StringEncoding]];
}

[body appendData:[[NSString stringWithFormat:@"--%@--rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

// setting the body of the post to the reqeust
[request setHTTPBody:body];

// set URL
[request setURL:requestURL];
  

Комментарии:

1. У вас когда-нибудь возникали проблемы с выполнением этой работы? Это почти точно мой код, и я даже изменил свой тип контента на «image / jpeg», как у вас. Возможно, моя проблема на стороне сервера, хотя я уверен, что это не так.

2. Никаких проблем, этот код работает в моем приложении для загрузки файлов JPG, снятых с камеры iPhone, на наш веб-сервер.

3. Не могли бы вы объяснить назначение имени файла =»image.jpg «? У меня этого нет в моем коде, я предположил, что это дополнительная информация, но, возможно, это необходимо?

4. Я хотел добавить комментарий здесь об этом коде. Возврат каретки и перевод строки, а также дополнительные тире имеют РЕШАЮЩЕЕ значение для того, как работает этот процесс. У вас должен быть двойной CR / LF в нужном месте и дополнительные тире в нужном месте. Я думал, что это просто так много лишнего, но это важно. Код XJone помог мне разобраться с моей проблемой, когда мне не хватало паршивого CR / LF, и моя загрузка не удалась. 1 для вас, сэр, и для этого вопроса.

5. Я не уверен. Я не писал код на стороне сервера, я отправляю в проприетарный API. Однако именование на сервере не влияет на код клиента.

Ответ №2:

я надеюсь, что этот код поможет кому-то еще…

 //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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"rnrn", param] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@rn", [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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="image.jpg"rn", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type:image/jpegrnrn" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:imageData];
    [body appendData:[[NSString stringWithFormat:@"rn"] dataUsingEncoding:NSUTF8StringEncoding]];
}

//Close off the request with the boundary
[body appendData:[[NSString stringWithFormat:@"--%@--rn", 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");
                           }

                       }];
  

Комментарии:

1. если у меня есть путь к изображению dev-demo.info.bh-in-15.webhostbox.net/dv/xyz/ulpoad/post / … тогда куда я должен поместить это в приведенный выше код

2. @Abhi NSData *ImageData = UIImageJPEGRepresentation(ImageObject, 1) замените эту строку .. загрузите изображение из path и преобразуйте в nsdata

3. это сбивает с толку, можете ли вы обновить его в своем ответе или в комментарии

4. @Abhi NSData *ImageData = [NSData dataWithContentOfFile:filePath]; укажите путь к файлу ur

Ответ №3:

Взгляните на пример проекта Apple SimpleURLConnections. Вы можете использовать PostController оттуда с несколькими изменениями.

Однако — это не совсем просто. Отличие от решения выше заключается в том, что Apple использует stream для передачи файла на сервер. Это гораздо удобнее для памяти, чем хранить закодированные данные изображения на протяжении всей загрузки. Это также намного сложнее.

Ответ №4:

 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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Disposition: form-data; name="file"; filename="a.jpg"rn" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/octet-streamrnrn" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imgData]];
[body appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

//  parameter UserId

[body appendData:[[NSString stringWithFormat:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="userid"rnrn"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[appDelegate.strUserID dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];


// close form
[body appendData:[[NSString stringWithFormat:@"--%@--rn", 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);
  

Комментарии:

1. большое вам спасибо за ваш код! другие фрагменты не работали, и разница с вашим заключалась в том, что вы закрываете форму границей.

Ответ №5:

Я вижу, что вы отправляете несколько файлов в одном запросе, верно?

Исходя из спецификации HTTP, вы должны использовать multipart / mixed Content-type внутри встраивания multipart / form-data

Пример по ссылке выше:

 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"
  

Комментарии:

1. вы знаете, как получить все данные в php из этого