使用Twitpic API上传图片时响应代码错误

时间:2009-07-27 13:12:23

标签: iphone objective-c twitter

任何熟悉使用“Twitpic api”将图片上传到Twitter的源代码的人都可以告诉我为什么在上传图片时会收到0响应代码?

这是我的代码:

- (BOOL)uploadImageToTwitpic:(UIImage*)image
                 withMessage:(NSString*)theMessage
                    username:(NSString*)username
                    password:(NSString*)password
{
    NSString *stringBoundary, *contentType, *message, *baseURLString, *urlString;
    NSData *imageData;
    NSURL *url;
    NSMutableURLRequest *urlRequest;
    NSMutableData *postBody;

    // Create POST request from message, imageData, username and password
    baseURLString = kTwitpicUploadURL;
    urlString = [NSString stringWithFormat:@"%@", baseURLString];
    url = [NSURL URLWithString:urlString];
    urlRequest = [[[NSMutableURLRequest alloc] initWithURL:url] autorelease];
    [urlRequest setHTTPMethod:@"POST"];

    // Set the params
    message = ([theMessage length] > 1) ? theMessage : @"Here's my new Light Table collage.";
    imageData = UIImageJPEGRepresentation(image, kTwitpicImageJPEGCompression);

    // Setup POST body
    stringBoundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"];
    contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", stringBoundary];
    [urlRequest addValue:contentType forHTTPHeaderField:@"Content-Type"];

    // Setting up the POST request's multipart/form-data body
    postBody = [NSMutableData data];
    [postBody appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"source\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"lighttable"] dataUsingEncoding:NSUTF8StringEncoding]]; // So Light Table show up as source in Twitter post

    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"username\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:username] dataUsingEncoding:NSUTF8StringEncoding]]; // username

    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"password\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:password] dataUsingEncoding:NSUTF8StringEncoding]]; // password

    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"message\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:message] dataUsingEncoding:NSUTF8StringEncoding]]; // message

    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"media\"; filename=\"%@\"\r\n", @"lighttable_twitpic_image.jpg" ] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Type: image/jpg\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; // jpeg as data
    [postBody appendData:[[NSString stringWithString:@"Content-Transfer-Encoding: binary\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:imageData]; // Tack on the imageData to the end

    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [urlRequest setHTTPBody:postBody];
    NSLog(@"data=======>%@",postBody);
    NSLog(@"URLReq========>%@",urlRequest);
    // Spawn a new thread so the UI isn't blocked while we're uploading the image
    [NSThread detachNewThreadSelector:@selector(uploadingDataWithURLRequest:) toTarget:self withObject:urlRequest];

    return YES; // TODO: Should raise exception on error
}

- (void)uploadingDataWithURLRequest:(NSURLRequest*)urlRequest {
    // Called on a separate thread; upload and handle server response

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [urlRequest retain]; // Retain since we autoreleased it before

    // Send the request
    NSHTTPURLResponse *urlResponse;
    NSError *error;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest
                                                 returningResponse:&urlResponse
                                                             error:&error];
    NSString *responseString = [[NSString alloc] initWithData:responseData
                                                     encoding:NSUTF8StringEncoding];

    // Handle the error or success
    // If error, create error message and throw up UIAlertView
    NSLog(@"Response Code: %d", [urlResponse statusCode]);
    if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300) {
        NSLog(@"urlResultString: %@", responseString);

        NSString *match = [responseString stringByMatching:@"http[a-zA-Z0-9.:/]*"]; // Match the URL for the twitpic.com post
        NSLog(@"match: %@", match);

        // Send back notice to delegate
        [delegate twitpicEngine:self didUploadImageWithResponse:match];
    }
    else {
        NSLog(@"Error while uploading, got 400 error back or no response at all: %@", [urlResponse statusCode]);
        [delegate twitpicEngine:self didUploadImageWithResponse:nil]; // Nil should mean "upload failed" to the delegate
    }

    [pool drain];
    [responseString release];
    [urlRequest release];
}

1 个答案:

答案 0 :(得分:1)

修改:我建议您阅读this SO question,看看创建POST请求的其他方式是否有帮助。


我自己并不熟悉Twitpic API,但我会尝试提出一些可以帮助您缩小问题范围的建议。

我要检查的第一件事是POST正文的正确性。你创建它的代码是不必要的复杂和难以阅读,所以如果它可能存在错误我不会感到惊讶。我发布了一个修订版本(免责声明,我没有编译它),简化了创建并提高了性能。 (您正在创建一个自动释放的NSString和NSData对象的TON,并且每次只是为了追加数据字节而将字符串转换为数据。构建可变字符串并转换一次是一种更快更简单的方法。)

与此相关的是,当在方法的顶部声明每个变量时,读取代码有点困难。这在最近的C(或派生语言)标准中是不必要的,并且在首次使用变量时声明变量被认为是更好的做法。它不仅使代码更容易阅读,而且通常会修剪几条不必要的行。

以下是包含一些建议修订的代码。它们可以更容易地找出问题所在。

- (BOOL)uploadImageToTwitpic:(UIImage*)image
                 withMessage:(NSString*)theMessage
                    username:(NSString*)username
                    password:(NSString*)password
{
    // Create POST request from message, imageData, username and password
    NSString *baseURLString = kTwitpicUploadURL;
    NSString *urlString = [NSString stringWithFormat:@"%@", baseURLString];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *urlRequest = [[[NSMutableURLRequest alloc] initWithURL:url] autorelease];
    [urlRequest setHTTPMethod:@"POST"];

    // Set the params
    NSString *message = ([theMessage length] > 1) ? theMessage : @"Here's my new Light Table collage.";

    // Setup POST body
    NSString *stringBoundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"];
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", stringBoundary];
    [urlRequest addValue:contentType forHTTPHeaderField:@"Content-Type"];

    NSString *stringBoundarySeparator = [NSString stringWithFormat:@"\r\n--%@\r\n", stringBoundary];

    NSMutableString *postString = [NSMutableString string];
    [postString appendString:@"\r\n"];
    [postString appendString:stringBoundarySeparator];
    [postString appendString:@"Content-Disposition: form-data; name=\"source\"\r\n\r\n"];
    [postString appendString:@"lighttable"]; // So Light Table shows up as source in Twitter 
    [postString appendString:stringBoundarySeparator];
    [postString appendStringWithFormat:@"Content-Disposition: form-data; name=\"username\"\r\n\r\n%@", username];
    [postString appendString:stringBoundarySeparator];
    [postString appendStringWithFormat:@"Content-Disposition: form-data; name=\"password\"\r\n\r\n%@", password];
    [postString appendString:stringBoundarySeparator];
    [postString appendStringWithFormat:@"Content-Disposition: form-data; name=\"message\"\r\n\r\n%@", message];
    [postString appendString:stringBoundarySeparator];
    [postString appendStringWithFormat:@"Content-Disposition: form-data; name=\"media\"; filename=\"%@\"\r\n", @"lighttable_twitpic_image.jpg"];
    [postString appendString:@"Content-Type: image/jpg\r\n"]; // data as JPEG
    [postString appendString:@"Content-Transfer-Encoding: binary\r\n\r\n"];

    // Setting up the POST request's multipart/form-data body
    NSMutableData *postBody = [NSMutableData data];
    [postBody appendData:[postString dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:UIImageJPEGRepresentation(image, kTwitpicImageJPEGCompression)]; // Tack on the image data to the end
    [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [urlRequest setHTTPBody:postBody];
    NSLog(@"data=======>%@",postBody);
    NSLog(@"URLReq========>%@",urlRequest);
    // Spawn a new thread so the UI isn't blocked while we're uploading the image
    [NSThread detachNewThreadSelector:@selector(uploadingDataWithURLRequest:) toTarget:self withObject:urlRequest];

    return YES; // TODO: Should raise exception on error
}

// Called on a separate thread; upload and handle server response
- (void)uploadingDataWithURLRequest:(NSURLRequest *)urlRequest {
    [urlRequest retain]; // Retain since we're using it in this method

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Send the request
    NSHTTPURLResponse *urlResponse;
    NSError *error;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest
                                                 returningResponse:&urlResponse
                                                             error:&error];
    NSString *responseString = [[[NSString alloc] initWithData:responseData
                                                      encoding:NSUTF8StringEncoding] autorelease];

    // Handle the error or success
    // If error, create error message and throw up UIAlertView
    NSLog(@"Response Code: %d", [urlResponse statusCode]);
    NSLog(@"Response String: %@", responseString);
    if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300) {
        NSString *match = [responseString stringByMatching:@"http[a-zA-Z0-9.:/]*"]; // Match the URL for the twitpic.com post
        NSLog(@"match: %@", match);
        // Send back notice to delegate
        [delegate twitpicEngine:self didUploadImageWithResponse:match];
    }
    else {
        NSLog(@"Error while uploading, got 400 error back or no response at all: %@", [urlResponse statusCode]);
        [delegate twitpicEngine:self didUploadImageWithResponse:nil]; // Nil should mean "upload failed" to the delegate
    }
    [pool drain];
    [urlRequest release];
}

有一件事可以帮助我们回答您的问题:您声明响应代码为0,但没有说出响应的其余部分(您在responseString中记录的)是什么。由于您只打印,如果状态代码在[200,300]范围内,您可能无法看到问题的原因,即使Twitpic 可能将其传回给您。值得一试......(我在上面的代码中完成了这个。)