2010-02-24 10 views
7

Este fragmento de código no funciona, recibo una "Error de autenticación". respuesta del servidor. ¿Algunas ideas?Enviando una solicitud POST de Cocoa a Tumblr

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

Tanto _tumblrLogin y _tumblrPassword se ejecutan a través stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding en otra parte de mi código. Mi correo electrónico de inicio de sesión es del tipo "[email protected]". Funciona muy bien para iniciar sesión directamente en tumblr, pero me pregunto si el carácter "+" está causando problemas con la codificación. No se está escapando. ¿Deberia ser?


Gracias a la sugerencia de Martin, ahora estoy usando CFURLCreateStringByAddingPercentEscapes a escapar de mi nombre de usuario y contraseña. Todavía tengo el mismo problema, sin embargo, mi Autenticación está fallando.

+0

¿Me puede decir la referencia de código de trabajo disponible para API Tumblr? – AppAspect

Respuesta

22

El problema es que no está creando una solicitud HTTP POST correcta. Una solicitud POST requiere un cuerpo con codificación MIME multiparte con formato adecuado que contenga todos los parámetros que desea enviar al servidor. Está intentando establecer los parámetros como encabezados HTTP que no funcionarán en absoluto.

Este código va a hacer lo que quiere, nota especialmente los NSString categorías que crean una cadena válida multiparte MIME:

@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 
+1

Holy crap. Me gustaría protagonizar este 10000x si pudiera. Gracias por tu ayuda. Mientras te tengo enganchado, ¿tienes un enlace que explique los campos header (por qué necesitas establecer la codificación de 8 bits) y MIMEBoundary? – kubi

+0

Debe establecer la codificación de 8 bits porque el cuerpo de la solicitud es un conjunto de datos codificados utilizando UTF8 (utilizando el método '-dataUsingEncoding:' de 'NSString' y pasando' NSUTF8StringEncoding'). UTF8 es una codificación de 8 bits, si se interpretara como una codificación de 7 bits (ASCII) se producirían daños en los datos. La codificación MIME multiparte le permite crear una cadena que contiene secciones separadas. Cada sección está delineada por una cadena constante utilizada como un marcador de límite. La cadena de límite es completamente arbitraria, pero no debe estar contenida en el contenido no delimitado de la cadena. –

+0

El artículo de Wikipedia sobre MIME es probablemente útil: http://en.wikipedia.org/wiki/MIME#Multipart_messages –

0

Según las respuestas a this question, stringByAddingPercentEscapesUsingEncoding: no realiza una codificación de escape completo. Por alguna razón, la versión CoreFoundation de este método, sin embargo:

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

También puede utilizar el método de NSMutableString replaceOccurencesOfString:withString:options: para hacer el reemplazo de forma manual, pero ese método es más repetitivo y detallado. (See here.)

+0

Gracias por esto. Utilicé el CFURLCreate ... según su sugerencia, pero todavía no está funcionando. – kubi

Cuestiones relacionadas