Cocoa URL API:如何从服务器返回错误*并且*仍然下载请求的数据?

时间:2012-05-18 16:20:46

标签: php cocoa nsurlconnection nsurl

有趣的编程难题......

我无法将错误初始化为nil,因此下面的代码会崩溃。

    NSString *query = [NSString stringWithFormat:@"http://mysite.com/getlatest.php?a=%@", aSuiteName];
    NSURL *url = [NSURL URLWithString:query];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:10];
    [request setHTTPMethod:@"GET"];
    NSURLResponse *response = nil;
    NSError *error;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if ( !data || error != nil ) {
        NSLog(@"Error downlading %@", error); //CRASH
        return NO;
    }

我的问题是,如何让我的服务器返回一个错误,例如sendSynchronousRequest:returningResponse:error:实际上收到错误,但仍然继续下载数据?某种非致命错误会导致错误被初始化为NSError对象吗?

这与类似的难题有关,我之前想要在没有完全失败的情况下返回状态信息。所以,虽然模糊不清,但我很想知道是否有这种技术。

虽然这是一个Cocoa问题,但我认为答案将在php中。像

这样的东西
<?php

    header( set 503 error here );

    return data;

?>

1 个答案:

答案 0 :(得分:0)

我通过将数据包装到NSError对象中来处理这个问题。在纯文本响应的情况下,我还将响应用作localizedDescription。我使用单独的方法来评估结果是否成功。如果URL请求本身生成错误,我也认为这是一个失败,并传递URL请求提供的NSError。

这是从我的ServerRequest类中删除的:

+ (NSError *) errorForStatusCode:(NSInteger) statusCode
                     contentType:(NSString *) contentType
                textEncodingName:(NSString *) textEncodingName
                            data:(NSData *) data {

    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    if ([contentType isEqualToString:@"text/plain"]) {
        [userInfo setValue:[[NSString alloc] initWithData:data encoding:[self stringEncodingForTextEncodingName:textEncodingName]]
                    forKey:NSLocalizedDescriptionKey];
    } else if ( ... ) {
        // handle other relevant types         
    }

    return [NSError errorWithDomain:[[self class] description]
                               code:statusCode
                           userInfo:userInfo];
}

- (BOOL) statusCodeIndicatesSuccess:(NSInteger) statusCodeValue {
    return 201 == statusCodeValue; // Modify this based on your API
}

- (BOOL) runSynchronouslyReturningResult:(NSData **) resultPtr error:(NSError **) errorPtr {
    NSHTTPURLResponse *response = nil;
    NSError *error = nil;
    NSData *result = [NSURLConnection sendSynchronousRequest:[self request] returningResponse:&response error:&error];
    if (error) {
        if (errorPtr) *errorPtr = error;
        return NO;
    }

    self.statusCode = [response statusCode];
    self.MIMEType = [response MIMEType];
    self.textEncodingName = [response textEncodingName];
    if ([self statusCodeIndicatesSuccess:self.statusCode]) {
        if (resultPtr) *resultPtr = result;
        return YES;
    } else {
        if (errorPtr) *errorPtr = [ServerRequest errorForStatusCode:self.statusCode
                                                        contentType:self.MIMEType
                                                   textEncodingName:self.textEncodingName
                                                               data:result];
        if (resultPtr) *resultPtr = result;
        return NO;
    }
}