All Products
Search
Document Center

HTTPDNS:Best practices for using HTTPDNS with AFNetworking on iOS

Last Updated:Dec 30, 2025

This document describes how to integrate HTTPDNS with AFNetworking on an iOS client.

1. Overview

AFNetworking is a popular networking framework for iOS development. It provides a simple API and powerful features. This document describes how to integrate HTTPDNS into a project that uses AFNetworking.

For basic information about HTTPDNS and the technical challenges of using it on iOS, see Use HTTPDNS in native iOS scenarios.

2. Integration for standard HTTP and non-SNI HTTPS scenarios

This method applies to standard HTTP scenarios and HTTPS scenarios that do not require Server Name Indication (SNI).

2.1 Create an AFHTTPSessionManager

+ (AFHTTPSessionManager *)sharedAfnManager {
    static AFHTTPSessionManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [AFHTTPSessionManager manager];
        
        // Configure the security policy.
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
        securityPolicy.allowInvalidCertificates = NO;
        securityPolicy.validatesDomainName = YES;
        manager.securityPolicy = securityPolicy;
        
        // Configure the serializer.
        manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects: 
            @"application/json", @"text/json", @"text/javascript", @"text/plain", nil];
        manager.requestSerializer.timeoutInterval = 10.0f;
    });
    return manager;
}

2.2 Perform HTTPDNS domain name resolution

+ (NSString *)resolveAvailableIp:(NSString *)host {
    HttpDnsService *httpDnsService = [HttpDnsService sharedInstance];
    HttpdnsResult *result = [httpDnsService resolveHostSyncNonBlocking:host 
                                                             byIpType:HttpdnsQueryIPTypeAuto];
    if (!result) return nil;
    
    if (result.hasIpv4Address) {
        return result.firstIpv4Address;
    } else if (result.hasIpv6Address) {
        return [NSString stringWithFormat:@"[%@]", result.firstIpv6Address];
    }
    return nil;
}

2.3 Send a network request and handle certificate validation

+ (void)httpDnsQueryWithURL:(NSString *)originalUrl 
          completionHandler:(void(^)(NSString *message))completionHandler {
    
    NSURL *url = [NSURL URLWithString:originalUrl];
    NSString *resolvedIpAddress = [self resolveAvailableIp:url.host];

    NSString *requestUrl = originalUrl;
    if (resolvedIpAddress) {
        // Replace the domain name with the resolved IP address.
        requestUrl = [originalUrl stringByReplacingOccurrencesOfString:url.host 
                                                           withString:resolvedIpAddress];
        NSLog(@"HTTPDNS resolution successful. Domain name: %@, IP address: %@", url.host, resolvedIpAddress);
    } else {
        NSLog(@"HTTPDNS resolution failed. Using original URL: %@", url.host);
    }

    AFHTTPSessionManager *manager = [self sharedAfnManager];
    
    // Important: Set the Host header to ensure the server correctly identifies the domain name.
    [manager.requestSerializer setValue:url.host forHTTPHeaderField:@"host"];
    
    // Important: Configure HTTPS certificate validation. Use the original domain name for validation.
    [manager setSessionDidReceiveAuthenticationChallengeBlock:
     ^NSURLSessionAuthChallengeDisposition(NSURLSession *session, 
                                          NSURLAuthenticationChallenge *challenge, 
                                          NSURLCredential **credential) {
        
        if ([challenge.protectionSpace.authenticationMethod 
             isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            
            if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust 
                               forDomain:url.host]) {
                *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                return NSURLSessionAuthChallengeUseCredential;
            }
        }
        return NSURLSessionAuthChallengePerformDefaultHandling;
    }];
    
    // Send the request.
    [manager GET:requestUrl parameters:nil headers:nil progress:nil 
         success:^(NSURLSessionDataTask *task, id responseObject) {
             NSData *data = [[NSData alloc] initWithData:responseObject];
             NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
             if (completionHandler) {
                 completionHandler([NSString stringWithFormat:@"Request successful: %@", dataStr]);
             }
         } 
         failure:^(NSURLSessionDataTask *task, NSError *error) {
             if (completionHandler) {
                 completionHandler([NSString stringWithFormat:@"Request failed: %@", error.localizedDescription]);
             }
         }];
}

+ (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
    // Create a certificate validation policy.
    NSMutableArray *policies = [NSMutableArray array];
    if (domain) {
        [policies addObject:(__bridge_transfer id) SecPolicyCreateSSL(true, (__bridge CFStringRef) domain)];
    } else {
        [policies addObject:(__bridge_transfer id) SecPolicyCreateBasicX509()];
    }
    
    // Attach the validation policy to the server certificate.
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef) policies);
    
    // Evaluate the certificate trust.
    SecTrustResultType result;
    SecTrustEvaluate(serverTrust, &result);
    
    return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
}

3. Integration for HTTPS with SNI scenarios

This method applies to scenarios that require SNI support, such as using a CDN or sharing an IP address among multiple domain names.

3.1 Configure an AFHTTPSessionManager that supports SNI

+ (AFHTTPSessionManager *)sharedAfnManagerWithSNI {
    static AFHTTPSessionManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        
        // Important: Register a custom NSURLProtocol to handle SNI.
        NSMutableArray *protocolsArray = [NSMutableArray arrayWithArray:configuration.protocolClasses];
        [protocolsArray insertObject:[HttpDnsNSURLProtocolImpl class] atIndex:0];
        [configuration setProtocolClasses:protocolsArray];
        
        manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
        
        // Configure the security policy.
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
        securityPolicy.allowInvalidCertificates = NO;
        securityPolicy.validatesDomainName = YES;
        manager.securityPolicy = securityPolicy;
        
        // Configure the serializer.
        manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects: 
            @"application/json", @"text/json", @"text/javascript", @"text/plain", nil];
        manager.requestSerializer.timeoutInterval = 10.0f;
    });
    return manager;
}

3.2 Perform HTTPDNS domain name resolution

+ (NSString *)resolveAvailableIp:(NSString *)host {
    HttpDnsService *httpDnsService = [HttpDnsService sharedInstance];
    HttpdnsResult *result = [httpDnsService resolveHostSyncNonBlocking:host 
                                                             byIpType:HttpdnsQueryIPTypeAuto];
    if (!result) return nil;
    
    if (result.hasIpv4Address) {
        return result.firstIpv4Address;
    } else if (result.hasIpv6Address) {
        return [NSString stringWithFormat:@"[%@]", result.firstIpv6Address];
    }
    return nil;
}

3.3 Send a network request in an SNI scenario

+ (void)httpDnsQueryWithSNIURL:(NSString *)originalUrl 
             completionHandler:(void(^)(NSString *message))completionHandler {
    
    NSURL *url = [NSURL URLWithString:originalUrl];
    NSString *resolvedIpAddress = [self resolveAvailableIp:url.host];

    NSString *requestUrl = originalUrl;
    if (resolvedIpAddress) {
        requestUrl = [originalUrl stringByReplacingOccurrencesOfString:url.host 
                                                           withString:resolvedIpAddress];
        NSLog(@"HTTPDNS resolution successful. Domain name: %@, IP address: %@", url.host, resolvedIpAddress);
    } else {
        NSLog(@"HTTPDNS resolution failed. Using original URL: %@", url.host);
    }

    AFHTTPSessionManager *manager = [self sharedAfnManagerWithSNI];
    
    // Set the Host header.
    [manager.requestSerializer setValue:url.host forHTTPHeaderField:@"host"];
    
    // Note: Because a custom NSURLProtocol is used, SNI and certificate validation are handled at the protocol layer.
    // Send the request directly.
    [manager GET:requestUrl parameters:nil headers:nil progress:nil 
         success:^(NSURLSessionDataTask *task, id responseObject) {
             NSData *data = [[NSData alloc] initWithData:responseObject];
             NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
             if (completionHandler) {
                 completionHandler([NSString stringWithFormat:@"Request successful: %@", dataStr]);
             }
         } 
         failure:^(NSURLSessionDataTask *task, NSError *error) {
             if (completionHandler) {
                 completionHandler([NSString stringWithFormat:@"Request failed: %@", error.localizedDescription]);
             }
         }];
}

Note: In SNI scenarios, certificate validation and domain name handling are automatically processed at the NSURLProtocol layer. You do not need to configure a separate certificate validation callback.

For a sample implementation, see the HttpDnsNSURLProtocolImpl.m file in the Alibaba Cloud httpdns_ios_demo. You can modify or reuse this implementation as needed.

4. Examples

4.1 Basic HTTPS request

// Standard HTTP request (non-SNI scenario)
[AFNHttpsScenario httpDnsQueryWithURL:@"http://example.com/api/data" 
                    completionHandler:^(NSString *message) {
    NSLog(@"Request result: %@", message);
}];

4.2 Request in an SNI scenario

// Request in an SNI scenario
[AFNHttpsWithSNIScenario httpDnsQueryWithSNIURL:@"https://example.com/api/data" 
                               completionHandler:^(NSString *message) {
    NSLog(@"Request result: %@", message);
}];

5. Summary

The core steps to integrate HTTPDNS with AFNetworking are:

  1. Initialize AFHTTPSessionManager: Configure basic network parameters.

  2. Perform HTTPDNS domain name resolution: Obtain an IP address to replace the domain name.

  3. Send the network request: Set the Host header and handle HTTPS certificate validation.

Key points

  • Host header: Ensure the server can correctly identify the requested domain name.

  • Certificate validation: Use the original domain name, not the IP address, for certificate validation.

  • SNI handling: Use NSURLProtocol for automatic handling in complex scenarios.

  • Fallback policy: Fall back to the system DNS if HTTPDNS resolution fails.

For the complete sample code, see HTTPDNS iOS Demo.