8

我正在努力使用 https 请求网络服务。我收到这种错误:

An error occured : The certificate for this server is invalid. You might be connecting to a server that is pretending to be “SERVER_ADDRESS” which could put your confidential information at risk.

我没有使用 NSUrlConnectionDelegate。这是我的方法:

- (void)sendRequestWithUrl:(NSURL*)url block:(void (^)(NSDictionary *dict, NSError *error)) block{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    NSError* err = nil;
    NSHTTPURLResponse* rsp = nil;
    // Perform the request synchronously on this thread
    NSData *rspData = [NSURLConnection sendSynchronousRequest:request returningResponse:&rsp error:&err];
    if (rspData && err == nil) {
        NSDictionary *result = [NSJSONSerialization JSONObjectWithData:rspData options:NSJSONReadingMutableLeaves error:&err];
        if(result) {
            block(result, err);
        } else {
            block(nil, err);
        }
    }else{
        DLog(@"Requesting URL: %@  An error occured : %@",url,[err localizedDescription]);
        block(nil, err);
    }
}

我怎么能解决这个问题?

4

5 回答 5

2

Apple 有一个技术说明很好地涵盖了这一点:

《技术说明 TN2232:HTTPS 服务器信任评估》

https://developer.apple.com/library/ios/#technotes/tn2232/_index.html

于 2013-02-19T02:45:59.990 回答
2

好吧,我的解决方案是创建AsyncURLConnection我在http://stackoverflow.com某处找到的代码类,但现在找不到。所以我会给出代码:

AsyncURLConnection

。H

#import <Foundation/Foundation.h>

typedef void (^completeBlock_t)(NSData *data);
typedef void (^errorBlock_t)(NSError *error);

@interface AsyncURLConnection : NSObject{
    NSMutableData *data_;
    completeBlock_t completeBlock_;
    errorBlock_t errorBlock_;
}

+ (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
- (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
+ (id)requestWithMutable:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
- (id)initWithMutableRequest:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
@end

.m

#import "AsyncURLConnection.h"

@implementation AsyncURLConnection

+ (id)requestWithMutable:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{
    return [[self alloc] initWithMutableRequest:request completeBlock:completeBlock errorBlock:errorBlock];
}

+ (id)request:(NSString*)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{
    return [[self alloc] initWithRequest:requestUrl
                            completeBlock:completeBlock errorBlock:errorBlock];
}

- (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{
    if ((self=[super init])) {
        data_ = [[NSMutableData alloc] init];
        completeBlock_ = [completeBlock copy];
        errorBlock_ = [errorBlock copy];
        NSURL *url = [NSURL URLWithString:requestUrl];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [NSURLConnection connectionWithRequest:request delegate:self];
    }
    return self;
}

- (id)initWithMutableRequest:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{
    if ((self=[super init])) {
        data_ = [[NSMutableData alloc] init];
        completeBlock_ = [completeBlock copy];
        errorBlock_ = [errorBlock copy];
        [NSURLConnection connectionWithRequest:request delegate:self];
    }
    return self;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [data_ setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [data_ appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    completeBlock_(data_);
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    errorBlock_(error);
}


- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge previousFailureCount] == 0)
    {
        NSURLCredential *newCredential;
        newCredential=[NSURLCredential credentialWithUser:@"someUser"
                                                 password:@"someUser"
                                              persistence:NSURLCredentialPersistenceForSession];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        DLog(@"responded to authentication challenge");

    }else{
        DLog(@"previous authentication failure");
    }
}

所以在一些控制器中可以使用这个类:

+ (void) downloadFileForURL:(NSURL *) url completionBlock:(void (^)(NSData *data, NSError *error)) block {
    NSString *requestURL = @"https://www.google.lt/restServer/Method";
    [AsyncURLConnection request:requestURL completeBlock:^(NSData *data) {
        /* success! */
        dispatch_queue_t downloadQueue = dispatch_queue_create("Download queue", NULL);
        dispatch_async(downloadQueue, ^{
            /* process downloaded data in Concurrent Queue */
            if (data != nil) {
                block(data, nil);
            }else{
                block(nil,nil);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                /* update UI on Main Thread */
            });
        });
    } errorBlock:^(NSError *error) {
        /* error! */
        block(nil,error);
    }];
}

希望有人这个代码可以帮助。

谢谢大家的回答。

于 2013-02-25T13:00:06.103 回答
1

您应该将以下委托方法添加到您的通信类。

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        if ([YOUR_HOST isEqualToString:challenge.protectionSpace.host])
        {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];           
        }
    }   
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
于 2013-02-24T05:52:54.907 回答
0

自签名证书总是会发生这种情况。通过使用NSURLConnectionDelegate

- (BOOL)connection:(NSURLConnection *)connection
canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        return YES;
    }
}
于 2013-02-19T09:45:35.350 回答
0

尝试这个委托方法为我解决了同样的问题。

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
于 2013-02-25T12:40:31.803 回答