Enviando uma solicitação POST do Cocoa para o Tumblr

Este snippet de código não está funcionando, estou recebendo uma mensagem “Falha na autenticação”. resposta do servidor. Alguma ideia?

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:@"http://www.tumblr.com/api/write"]]; [request setHTTPMethod:@"POST"]; [request addValue:_tumblrLogin forHTTPHeaderField:@"email"]; [request addValue:_tumblrPassword forHTTPHeaderField:@"password"]; [request addValue:@"regular" forHTTPHeaderField:@"type"]; [request addValue:@"theTitle" forHTTPHeaderField:@"title"]; [request addValue:@"theBody" forHTTPHeaderField:@"body"]; NSLog(@"Tumblr Login:%@\nTumblr Password:%@", _tumblrLogin, _tumblrPassword); [NSURLConnection connectionWithRequest:request delegate:self]; [request release]; 

Ambos _tumblrLogin e _tumblrPassword são executados através de stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding em outro lugar no meu código. Meu e-mail de login está no formato “address+test@test.com”. Ele funciona muito bem para fazer login diretamente no tumblr, mas eu estou querendo saber se o caractere “+” está causando problemas com a codificação? Não está sendo escapado. Deveria ser?


Graças à sugestão de Martin, estou usando agora CFURLCreateStringByAddingPercentEscapes para escaping do meu login e senha. Ainda estou tendo o mesmo problema, porém, minha autenticação está falhando.

O problema é que você não está criando uma solicitação HTTP POST apropriada. Uma solicitação POST exige um corpo codificado em MIME multipart com formatação adequada contendo todos os parâmetros que você deseja enviar ao servidor. Você está tentando definir os parâmetros como headers HTTP que não funcionam.

Este código irá fazer o que você quer, note especialmente as categorias NSString que criam uma string MIME Multipart válida:

 @interface NSString (MIMEAdditions) + (NSString*)MIMEBoundary; + (NSString*)multipartMIMEStringWithDictionary:(NSDictionary*)dict; @end @implementation NSString (MIMEAdditions) //this returns a unique boundary which is used in constructing the multipart MIME body of the POST request + (NSString*)MIMEBoundary { static NSString* MIMEBoundary = nil; if(!MIMEBoundary) MIMEBoundary = [[NSString alloc] initWithFormat:@"----_=_YourAppNameNoSpaces_%@_=_----",[[NSProcessInfo processInfo] globallyUniqueString]]; return MIMEBoundary; } //this create a correctly structured multipart MIME body for the POST request from a dictionary + (NSString*)multipartMIMEStringWithDictionary:(NSDictionary*)dict { NSMutableString* result = [NSMutableString string]; for (NSString* key in dict) { [result appendFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n",[NSString MIMEBoundary],key,[dict objectForKey:key]]; } [result appendFormat:@"\r\n--%@--\r\n",[NSString MIMEBoundary]]; return result; } @end @implementation YourObject - (void)postToTumblr { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:@"http://www.tumblr.com/api/write"]]; [request setHTTPMethod:@"POST"]; //tell the server to expect 8-bit encoded content as we're sending UTF-8 data, //and UTF-8 is an 8-bit encoding [request addValue:@"8bit" forHTTPHeaderField:@"Content-Transfer-Encoding"]; //set the content-type header to multipart MIME [request addValue: [NSString stringWithFormat:@"multipart/form-data; boundary=%@",[NSString MIMEBoundary]] forHTTPHeaderField: @"Content-Type"]; //create a dictionary for all the fields you want to send in the POST request NSDictionary* postData = [NSDictionary dictionaryWithObjectsAndKeys: _tumblrLogin, @"email", _tumblrPassword, @"password", @"regular", @"type", @"theTitle", @"title", @"theBody", @"body", nil]; //set the body of the POST request to the multipart MIME encoded dictionary [request setHTTPBody: [[NSString multipartMIMEStringWithDictionary: postData] dataUsingEncoding: NSUTF8StringEncoding]]; NSLog(@"Tumblr Login:%@\nTumblr Password:%@", _tumblrLogin, _tumblrPassword); [NSURLConnection connectionWithRequest:request delegate:self]; [request release]; } @end 

De acordo com as respostas a essa pergunta , stringByAddingPercentEscapesUsingEncoding: não executa uma codificação de escape completa. Por qualquer motivo, a versão CoreFoundation desse método faz, no entanto:

 [(NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)[[self mutableCopy] autorelease], NULL, CFSTR("=,!$&'()*+;@?\n\"<>#\t :/"), kCFStringEncodingUTF8) autorelease]; 

Você também pode usar o replaceOccurencesOfString:withString:options: do NSMutableString para fazer a substituição manualmente, mas esse método é mais repetitivo e detalhado. ( Veja aqui )