2010-02-24 6 views
7

Dieses Code-Snippet funktioniert nicht, ich bekomme eine "Authentifizierung fehlgeschlagen." Antwort vom Server. Irgendwelche Ideen?Senden einer POST-Anfrage von Cocoa an 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]; 

Sowohl _tumblrLogin und _tumblrPassword durch stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding an anderer Stelle in meinem Code ausführen. Meine Login-E-Mail hat die Form "Adresse + [email protected]". Es funktioniert gut für die Anmeldung direkt in Tumblr, aber ich frage mich, ob das "+" - Zeichen Probleme mit der Codierung verursacht? Es wird nicht entkommen. Sollte es sein?


Dank Martin Vorschlag, verwende ich jetzt CFURLCreateStringByAddingPercentEscapes mein Login und Passwort zu entkommen. Ich habe immer noch das gleiche Problem, aber meine Authentifizierung schlägt fehl.

+0

Können Sie mir den Arbeitscode Referenz für Tumblr API zur Verfügung sagen? – AppAspect

Antwort

22

Das Problem besteht darin, dass Sie keine ordnungsgemäße HTTP-POST-Anforderung erstellen. Eine POST-Anforderung erfordert einen ordnungsgemäß formatierten mehrteiligen MIME-codierten Textkörper, der alle Parameter enthält, die Sie an den Server senden möchten. Sie versuchen, die Parameter als HTTP-Header festzulegen, die überhaupt nicht funktionieren.

Dieser Code wird tun, was Sie wollen, beachten Sie vor allem die NSString Kategorien, die eine gültige Multipart MIME-Zeichenfolge zu erstellen:

@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

Heiliger Mist. Ich würde diese 10000x Sterne, wenn ich könnte. Danke für Ihre Hilfe. Während ich dich am Haken habe, hast du zufällig einen Link, der die headerFields erklärt (warum musst du die 8bit Kodierung einstellen) und die MIMEBoundary? – kubi

+0

Sie müssen die 8-Bit-Codierung festlegen, da der Hauptteil der Anforderung ein Datenblock ist, der mit UTF8 codiert ist (mit der '-dataUsingEncoding:' -Methode von 'NSString' und der Übergabe von 'NSUTF8StringEncoding'). UTF8 ist eine 8-Bit-Codierung, wenn es als eine 7-Bit-Codierung (ASCII) Daten Korruption interpretiert würde auftreten. Mit der mehrteiligen MIME-Codierung können Sie eine Zeichenfolge erstellen, die separate Abschnitte enthält. Jeder Abschnitt ist durch eine konstante Zeichenfolge gekennzeichnet, die als Begrenzungsmarkierung verwendet wird. Die Begrenzungszeichenfolge ist vollständig willkürlich, darf aber nicht im Inhalt ohne Begrenzung der Zeichenfolge enthalten sein. –

+0

Der Wikipedia-Artikel über MIME ist wahrscheinlich nützlich: http://en.wikipedia.org/wiki/MIME#Multipart_messages –

0

Gemäß den Antworten auf this question führt stringByAddingPercentEscapesUsingEncoding: keine vollständige Escape-Codierung durch. Aus irgendeinem Grunde hat die Corefoundation-Version dieser Methode ist jedoch:

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

Sie auch NSMutableString der replaceOccurencesOfString:withString:options: Methode zu tun, um den Ersatz manuell, aber das Verfahren ist repetitiv und ausführliches verwenden können. (See here.)

+0

Danke dafür. Ich habe die CFURLCreate ... nach Ihrem Vorschlag verwendet, aber es funktioniert immer noch nicht. – kubi