2010-02-24 41 views
7

Đoạn mã này không hoạt động, tôi nhận được "Xác thực không thành công". phản hồi từ máy chủ. Ý tưởng nào?Gửi yêu cầu POST từ Cocoa đến 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]; 

Cả _tumblrLogin_tumblrPassword đang chạy qua stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ở nơi khác trong mã của tôi. Email đăng nhập của tôi có dạng "[email protected]". Nó hoạt động tốt cho việc đăng nhập trực tiếp vào tumblr, nhưng tôi tự hỏi liệu ký tự "+" có gây ra vấn đề với mã hóa không? Nó không bị trốn thoát. Nó phải được?


Nhờ đề xuất của Martin, tôi hiện đang sử dụng CFURLCreateStringByAddingPercentEscapes để thoát khỏi thông tin đăng nhập và mật khẩu của mình. Tôi vẫn gặp sự cố tương tự, tuy nhiên, Xác thực của tôi không thành công.

+0

Bạn có thể cho tôi biết tài liệu tham khảo mã làm việc có sẵn cho Tumblr API? – AppAspect

Trả lời

22

Vấn đề là bạn không tạo yêu cầu HTTP POST thích hợp. Yêu cầu POST yêu cầu một phần tử được mã hóa MIME được định dạng đúng có chứa tất cả các tham số bạn muốn gửi tới máy chủ. Bạn đang cố gắng đặt tham số làm tiêu đề HTTP không hoạt động.

Mã này sẽ làm những gì bạn muốn, lưu ý đặc biệt là NSString danh mục tạo ra một chuỗi Multipart MIME hợp lệ:

@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. Tôi muốn ngôi sao này 10000x nếu tôi có thể. Cảm ơn bạn đã giúp đỡ. Trong khi tôi đã có bạn trên móc, bạn có xảy ra để có một liên kết giải thích headerFields (tại sao bạn cần phải thiết lập mã hóa 8bit) và MIMEBoundary? – kubi

+0

Bạn cần đặt mã hóa 8 bit vì phần thân của yêu cầu là một blob dữ liệu được mã hóa bằng UTF8 (sử dụng phương thức '-dataUsingEncoding:' của 'NSString' và chuyển vào' NSUTF8StringEncoding'). UTF8 là mã hóa 8 bit, nếu nó được hiểu là tham nhũng dữ liệu mã hóa 7 bit (ASCII) sẽ xảy ra. Mã hóa Multipart MIME cho phép bạn tạo một chuỗi chứa các phần riêng biệt. Mỗi phần được mô tả bằng một chuỗi không đổi được sử dụng làm điểm đánh dấu ranh giới. Chuỗi ranh giới là hoàn toàn tùy ý nhưng không được chứa trong nội dung không phải là ranh giới của chuỗi. –

+0

Bài viết trên Wikipedia về MIME có thể hữu ích: http://en.wikipedia.org/wiki/MIME#Multipart_messages –

0

Theo câu trả lời cho this question, stringByAddingPercentEscapesUsingEncoding: không thực hiện mã hóa thoát hoàn toàn. Đối với bất cứ lý do nào, phiên bản CoreFoundation của phương pháp này thực hiện, tuy nhiên:

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

Bạn cũng có thể sử dụng phương pháp replaceOccurencesOfString:withString:options: NSMutableString để làm việc thay thế bằng tay, nhưng phương pháp đó là lặp đi lặp lại hơn và tiết. (See here.)

+0

Cảm ơn vì điều này. Tôi đã sử dụng CFURLCreate ... theo đề xuất của bạn, nhưng nó vẫn không hoạt động. – kubi

Các vấn đề liên quan