Integre o SDK do HTTPDNS para iOS ao seu aplicativo e garanta uma resolução de nomes de domínio confiável com cache integrado.
Visão geral
O SDK para iOS encapsula a DoH JSON API do HTTPDNS. Ele fornece APIs para resolução de nomes de domínio em aplicativos iOS e oferece um mecanismo eficiente de cache de nomes de domínio, baseado nas políticas Time-to-Live (TTL) e Least Recently Used (LRU). Integre o HTTPDNS ao seu aplicativo iOS para corrigir anomalias na resolução de nomes de domínio e obter um agendamento de resolução preciso e de baixo custo.
Você também pode definir o HTTPDNS como o resolvedor DNS criptografado padrão por meio da solução nativa de DNS criptografado do iOS 14.
Principais benefícios:
-
Facilidade de uso:
A integração do HTTPDNS ao seu aplicativo exige pouquíssimo código.
-
Latência zero:
Um cache LRU interno armazena os IPs resolvidos localmente e atualiza proativamente as entradas expiradas, permitindo resoluções com latência zero.
Projeto de exemplo em Objective-C: código-fonte do projeto de exemplo alidns_ios_demo.
Projeto de exemplo em Swift: código-fonte do projeto de exemplo DNSResolverSwiftDemo.
Integração do SDK
Importar o SDK
CocoaPods
-
No Podfile, especifique a localização do repositório. Certifique-se de incluir o repositório master.
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/aliyun/aliyun-specs.git' -
Adicione a dependência ao target do seu projeto:
pod 'AlicloudPDNS'
Manual
Baixe o SDK para iOS em SDK Download.
Após obter o framework do SDK
pdns-sdk-ios.framework, adicione-o manualmente ao seu projeto.-
Importe as bibliotecas de sistema necessárias:
Foundation.framework
SystemConfiguration.framework
CoreFoundation.framework
CoreTelephony.framework
Nas Build Settings do seu projeto, adicione a flag -ObjC em Other Linker Flags.
Inicialização do SDK
Registre seu aplicativo no console para obter o Account ID e as credenciais AccessKey antes da inicialização.
Para evitar falhas na resolução, inicialize o SDK o mais cedo possível no ciclo de vida do seu aplicativo.
Inicialize o SDK no método application:didFinishLaunchingWithOptions:.
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// Specify domains for automatic cache updates. The array can contain a maximum of 10 domains.
[resolver setKeepAliveDomains:@[@"your_domain_1", @"your_domain_2"]];
// Pre-resolve domains that you expect to use later.
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// All domains are pre-resolved.
}];
Referência da API
Configurações comuns
1. Account ID e autenticação
Obrigatório. O console gera um Account ID exclusivo quando você registra seu aplicativo. Create an AccessKey pair para criar um AccessKey destinado à autenticação e, em seguida, configure-o:
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[[DNSResolver share] setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
Para evitar que seu Account ID, AccessKey ID ou AccessKey Secret fiquem expostos em logs ou outros dados gerados pelo aplicativo em execução, desative o log de depuração do SDK na versão de produção.
Para fins de demonstração, o código de exemplo passa o Account ID, o AccessKey ID e o AccessKey Secret diretamente. Essas credenciais são usadas para faturamento. Para evitar exposição por descompilação maliciosa, não codifique credenciais em texto simples no seu aplicativo de produção. Em vez disso, codifique-as ou criptografe-as e faça a decodificação ou descriptografia apenas quando necessário. Recomendamos também ofuscar e proteger o código do seu aplicativo. Caso contrário, seu Account ID, AccessKey ID e AccessKey Secret poderão ser comprometidos.
2. Definir o protocolo de resolução
Defina o protocolo de resolução (HTTP ou HTTPS) usando a propriedade scheme.
Por padrão, o SDK utiliza e recomenda o protocolo HTTPS, pois ele oferece maior segurança. O HTTPDNS é faturado com base no número de solicitações de resolução. As solicitações HTTPS são cobradas a uma taxa cinco vezes superior à das solicitações HTTP. Selecione o tipo de scheme conforme as necessidades do seu negócio. Defina a propriedade da seguinte forma:
[DNSResolver share].scheme = DNSResolverSchemeHttps;
3. Ativar ou desativar o cache
Quando ativado, os resultados resolvidos são armazenados em cache localmente, de modo que as consultas subsequentes retornam instantaneamente a partir do cache.
O cache vem ativado por padrão. Para desativá-lo, use o seguinte código:
[DNSResolver share].cacheEnable=NO;
4. Definir cache keep-alive para domínios
Quando ativado, o SDK atualiza proativamente as entradas de cache dos domínios especificados antes que expirem. Isso mantém os dados atuais, mas aumenta as solicitações de resolução e o tráfego de rede. Sem esse recurso, as atualizações de cache ocorrem apenas quando um método de resolução é chamado.
// The array can contain a maximum of 10 domains.
[[DNSResolver share] setKeepAliveDomains:@[@"www.taobao.com",@"www.aliyun.com"]];
-
Vantagens:
Os registros são atualizados prontamente (antes que o TTL expire).
Quando combinado com a pré-resolução, pode reduzir a latência inicial de resolução para 0 ms.
Desvantagem: Refazer solicitações a 75% do TTL de um registro gera custos adicionais.
5. Pré-resolução
Pré-resolva domínios na inicialização do aplicativo para que as consultas subsequentes acessem o cache com latência próxima de zero.
Exemplo de código:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
resolver.cacheEnable = YES;
// Pre-resolve domains that you expect to use later.
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// All domains are pre-resolved.
}];
return YES;
}
Configurações avançadas
1. Habilitar acesso IPv6 no servidor
O service HTTPDNS suporta acesso dual-stack (IPv4 e IPv6). Por padrão, o SDK usa IPv4.
Para usar IPv6, certifique-se de que sua rede ofereça suporte a esse protocolo e ative este recurso:
[DNSResolver share].ipv6Enable = YES;
2. Modo curto
A API DoH JSON do HTTPDNS retorna um JSON completo ou um array simplificado de IPs. O SDK usa o JSON completo por padrão.
Para usar o formato simplificado de array de IP:
[DNSResolver share].shortEnable = YES;
3. Definir o tamanho do cache
Se o cache estiver ativado, você poderá personalizar o número de domínios a serem armazenados. O intervalo suportado vai de 100 a 500.
O tamanho padrão do cache é de 100 domínios. Para definir um tamanho personalizado, use a propriedade cacheCountLimit:
[DNSResolver share].cacheCountLimit = 200;
4. Ativar ou desativar o teste de velocidade de IP
Com o teste de velocidade de IP ativado, os resultados da resolução são ordenados por latência, e o IP mais rápido é retornado primeiro.
A partir da versão 2.3.1 do SDK, o teste de velocidade de IP vem ativado por padrão (YES). Nas versões anteriores, ele fica desativado por padrão (NO). Para configurar esse recurso explicitamente, use o seguinte código:
[DNSResolver share].speedTestEnable=YES;
5. Definir o método de teste de velocidade de IP
Configure o método de sondagem: defina como 0 para sondagem ICMP ou como um número de porta (80, 443 etc.) para sondagem via socket nessa porta específica.
A partir da versão 2.3.1 do SDK, a porta padrão é 80. Nas versões anteriores, a porta padrão é 443.
[DNSResolver share].speedPort = 80;
6. Definir a desvantagem no teste de velocidade IPv6 (suportado desde a v2.3.1)
Defina uma desvantagem (handicap) para o teste de velocidade IPv6 em milissegundos. Quando um resultado de resolução contém endereços IPv4 e IPv6, o SDK subtrai essa desvantagem da latência IPv6 medida antes de compará-la com a latência IPv4. Assim, um endereço IPv6 ainda será preferido mesmo que seja marginalmente mais lento, desde que a diferença permaneça dentro da desvantagem configurada. O intervalo válido é de 0 a 1000. Essa configuração só tem efeito quando o teste de velocidade de IP está ativado.
O valor padrão é 0, o que desativa a desvantagem. Para definir uma desvantagem personalizada, use o seguinte código:
[DNSResolver share].speedTestIpv6PreferMs = 0;
7. Ativar ou desativar o cache de nomes de domínio específico por ISP
Quando ativado, as entradas de cache ficam isoladas por rede de ISP. Quando desativado, todas as redes compartilham um único cache.
O cache de nomes de domínio específico por ISP vem ativado por padrão.
[DNSResolver share].ispEnable = YES;
8. Definir o TTL máximo para o cache negativo
Defina um TTL máximo para o cache negativo, que armazena resultados de consultas com falha.
O valor padrão é 30s. Para definir um TTL máximo personalizado para o cache negativo, use o seguinte código:
[DNSResolver share].maxNegativeCache = 30;
9. Definir o TTL máximo do cache
Defina um TTL máximo para limitar a vida útil das entradas, independentemente dos valores de TTL fornecidos pelo servidor.
O valor padrão é 3600s. Para definir um TTL máximo personalizado, use o seguinte código:
[DNSResolver share].maxCacheTTL= 3600;
10. Ativar cache imutável
[DNSResolver share].immutableCacheEnable = NO;// Immutable cache is disabled by default.
O SDK fornece três mecanismos de atualização de cache:
-
Cache imutável: Com esse recurso ativado, o cache é tratado como sempre válido durante a execução do aplicativo. O SDK ignora verificações de expiração e atualizações, minimizando o número de solicitações de resolução.
Para ativá-lo, chame:
[DNSResolver share].immutableCacheEnable = YES -
Atualização ativa de cache: Mantém os resultados de resolução em cache sempre atualizados. Quando o registro autoritativo de um domínio muda, as solicitações ainda se beneficiam de acertos de cache de baixa latência enquanto o SDK atualiza os registros armazenados. O array aceita no máximo 10 domínios.
Para ativá-la, chame:
[[DNSResolver share] setKeepAliveDomains:@[@"your_domain_1",@"your_domain_2"]] -
Atualização passiva de cache: O cache é atualizado passivamente quando você chama um dos dois métodos a seguir para obter resultados de resolução:
O método
- (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))completeobtém um array de endereços IPv4 para um domínio. Se o cache não estiver vazio e a entrada estiver dentro do TTL, o método retorna o resultado em cache imediatamente. Caso contrário, ele busca o resultado mais recente pela rede, retorna-o e atualiza o cache. Use este método em cenários que exigem alta precisão.-
O método
- (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enablerecupera resultados de resolução IPv4 do cache. O comportamento deste método depende do parâmetroenable.Descrição do parâmetro: Se
enableforYES, o método retorna um registro obsoleto mesmo que o cache tenha expirado (ounilse o cache estiver vazio) e, em seguida, atualiza o cache de forma assíncrona. Se forNO, ele retornanilquando o cache estiver expirado ou vazio e, em seguida, atualiza o cache de forma assíncrona.
11. Timeout
A propriedade timeout define o timeout da solicitação para resolução. Padrão: 3s. Intervalo recomendado: 2s a 5s.
12. Definir o número máximo de solicitações simultâneas de resolução (suportado desde a v2.3.1)
Defina o número máximo de solicitações simultâneas de resolução DNS que o SDK envia. O intervalo válido é de 1 a 50. O valor padrão é 10. Para definir um limite personalizado, use o seguinte código:
[DNSResolver share].maxConcurrentResolveCount = 10;
APIs de service
Exemplo de código:
/// Pre-resolves domain information. Call this method at app startup. The results are stored in the cache to accelerate subsequent resolutions.
/// Automatically detects the network environment (IPv4-only, IPv6-only, or dual-stack) to get an IP suitable for the current network.
/// @param domainArray An array of domain names.
/// @param complete A callback that is executed after resolution is complete.
- (void)preloadDomains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// Gets an array of IP addresses for a domain. This method automatically detects the network environment (IPv4-only, IPv6-only, or dual-stack) to get a suitable IP.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IP over the network. If caching is disabled, it always fetches the IP over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all IP addresses.
- (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// Gets an array of IP addresses directly from the cache without waiting. This method automatically detects the network environment (IPv4-only, IPv6-only, or dual-stack).
/// Returns nil if the cache is empty. If the cache is not empty and `enable` is set to YES, it returns the cached data. If the data is expired, it asynchronously updates the cache. If the cache is not empty and `enable` is set to NO, it returns nil for expired entries and asynchronously updates the cache.
/// @param domain The domain name.
/// @param enable Specifies whether to return expired IP addresses.
- (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// Gets an array of IPv4 information objects for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IPs over the network. If caching is disabled, it always fetches the IPs over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all domain information objects.
- (void)getIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete;
/// Gets an array of IPv6 information objects for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IPs over the network. If caching is disabled, it always fetches the IPs over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all domain information objects.
- (void)getIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete;
/// Gets a random IPv4 information object for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IP over the network. If caching is disabled, it always fetches the IP over the network.
/// @param domain The domain name.
/// @param complete A callback that returns one random domain information object.
- (void)getRandomIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete;
/// Gets a random IPv6 information object for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IP over the network. If caching is disabled, it always fetches the IP over the network.
/// @param domain The domain name.
/// @param complete A callback that returns one random domain information object.
- (void)getRandomIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete;
/// Gets an array of IPv4 addresses for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IPs over the network. If caching is disabled, it always fetches the IPs over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all IP addresses.
- (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// Gets an array of IPv6 addresses for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IPs over the network. If caching is disabled, it always fetches the IPs over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all IP addresses.
- (void)getIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// Gets a random IPv4 address for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IP over the network. If caching is disabled, it always fetches the IP over the network.
/// @param domain The domain name.
/// @param complete A callback that returns one random IP address.
- (void)getRandomIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete;
/// Gets a random IPv6 address for a domain.
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IP over the network. If caching is disabled, it always fetches the IP over the network.
/// @param domain The domain name.
/// @param complete A callback that returns one random IP address.
- (void)getRandomIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete;
/// Pre-resolves IPv4 information for domains. Call this at app startup. The results are stored in the cache to accelerate subsequent resolutions.
/// @param domainArray An array of domain names.
/// @param complete A callback that is executed after resolution is complete.
- (void)preloadIpv4Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// Pre-resolves IPv6 information for domains. Call this at app startup. The results are stored in the cache to accelerate subsequent resolutions.
/// @param domainArray An array of domain names.
/// @param complete A callback that is executed after resolution is complete.
- (void)preloadIpv6Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// Gets an array of IPv4 addresses directly from the cache without waiting.
/// Returns nil if the cache is empty. If the cache is not empty and `enable` is set to YES, it returns the cached data. If the data is expired, it asynchronously updates the cache. If the cache is not empty and `enable` is set to NO, it returns nil for expired entries and asynchronously updates the cache.
/// @param domain The domain name.
/// @param enable Specifies whether to return expired IP addresses.
- (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// Gets an array of IPv6 addresses directly from the cache without waiting.
/// Returns nil if the cache is empty. If the cache is not empty and `enable` is set to YES, it returns the cached data. If the data is expired, it asynchronously updates the cache. If the cache is not empty and `enable` is set to NO, it returns nil for expired entries and asynchronously updates the cache.
/// @param domain The domain name.
/// @param enable Specifies whether to return expired IP addresses.
- (NSArray<NSString *> *)getIpv6ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// Collects request statistics.
-(NSArray *)getRequestReportInfo;
Exemplos de uso da API
1. Definir informações básicas
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Initialization method
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// Specify domains for automatic cache updates. The array can contain a maximum of 10 domains.
[resolver setKeepAliveDomains:@[@"your_domain_1",@"your_domain_2"]];
// Pre-resolve domains to get resolution results in advance and store them in the cache.
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// All domains are pre-resolved.
}];
return YES;
}
2. Usar a API de resolução de nomes de domínio
O SDK fornece vários métodos de resolução em DNSResolver.h. O exemplo abaixo usa um método que se adapta automaticamente ao ambiente de rede (somente IPv4, somente IPv6 ou dual-stack).
Declaração da API:
/// Gets an array of IP addresses for a domain. This method automatically adapts to the network environment (IPv4-only, IPv6-only, or dual-stack).
/// If caching is enabled, it returns data from the cache first. If the cache is empty or expired, it fetches the IPs over the network. If caching is disabled, it always fetches the IPs over the network.
/// @param domain The domain name.
/// @param complete A callback that returns all IP addresses.
- (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
Exemplo de chamada da API:
[[DNSResolver share] getIpsDataWithDomain:@"www.taobao.com" complete:^(NSArray<NSString *> *dataArray) {
// dataArray is the array of IP addresses for www.taobao.com.
if (dataArray.count > 0) {
//TODO: Use an IP address for the URL connection.
}
}];
3. Obter resultados de resolução diretamente do cache
Declaração da API:
/// Gets an array of IP addresses directly from the cache without waiting. This method automatically adapts to the network environment (IPv4-only, IPv6-only, or dual-stack).
/// Returns nil if the cache is empty. If the cache is not empty and `enable` is set to YES, it returns the cached data. If the data is expired, it asynchronously updates the cache. If the cache is not empty and `enable` is set to NO, it returns nil for expired entries and asynchronously updates the cache.
/// @param domain The domain name.
/// @param enable Specifies whether to return expired IP addresses.
- (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
Exemplo de chamada:
NSArray *result = [[DNSResolver share] getIpsByCacheWithDomain:@"your_domain" andExpiredIPEnabled:YES];
// Use the cached result.
if (result.count > 0) {
//TODO: Use an IP address for the URL connection.
}
Observação: Recuperar resultados diretamente do cache é rápido, mas o método retorna nil se o cache estiver vazio ou se o cache estiver expirado e enable estiver definido como NO.
4. Limpar o cache
Declaração da API:
/// `hostArray` is an array of hostnames to clear from the cache. To clear all data, pass nil or an empty array.
-(void)clearHostCache:(NSArray <NSString *>*)hostArray;
Exemplo de chamada:
[[DNSResolver share] clearHostCache:@[@"domain1", @"domain2"]];
5. Coletar estatísticas
Declaração da API:
/// Collects request statistics.
-(NSArray *)getRequestReportInfo;
Exemplo de chamada:
NSArray *array = [[DNSResolver share] getRequestReportInfo];
Formato dos dados:
(
{
avgRtt = "1"; // Average domain resolution time (ms)
cacheDnsNum = 0; // Number of cache hits
domain = "www.taobao.com"; // The resolved domain
gobackLocaldnsNum = 0; // Number of fallbacks to local DNS
localErro = 0; // Number of local DNS resolution failures
maxRtt = "60"; // Maximum domain resolution time (ms)
noPermissionErro = 0; // Number of authentication failures
noResponseErro = 0; // Number of no-response errors
requestPDnsNum = 1; // Number of recursive queries
sp = "China Mobile"; // ISP name
successNum = 1; // Number of successful resolutions
timeoutErro = 0; // Number of network timeout errors
type = 28; // IP type: 1 for IPv4, 28 for IPv6
urlParameterErro = 0; // Number of URL parameter format errors
urlPathErro = 0; // Number of URL path errors
}
......
);
Melhores práticas para resolução de nomes de domínio
Combine a pré-resolução com a estratégia stale-while-revalidate para obter desempenho ideal.
Pré-resolver domínios essenciais na inicialização preenche o cache, evitando idas e vindas pela rede nas consultas subsequentes e alcançando resolução com latência próxima de zero.
O cache integrado atende às solicitações subsequentes diretamente da memória.
1. Pré-resolução
Ative o cache e pré-resolva domínios essenciais na inicialização do aplicativo.
No método application:didFinishLaunchingWithOptions: do AppDelegate, pré-resolva os nomes de domínio usados no seu aplicativo e armazene os resultados na memória local.
1. Para cenários somente IPv4
//******** For IPv4-only scenarios *******
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// Enable caching. Default is YES.
resolver.cacheEnable = YES;
// Pre-resolve IPv4 information for domains that you expect to use later.
[resolver preloadIpv4Domains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// All domains are pre-resolved.
}];
return YES;
}
2. Para cenários IPv6
//******** For dual-stack scenarios that support IPv6 *******
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": Replace the asterisks with the Account ID from the Access Configuration page in the console.
// andAccessKeyId:@"********": Replace the asterisks with the AccessKey ID of the key that you created on the Access Configuration page.
// andAccesskeySecret:@"********": Replace the asterisks with the AccessKey Secret of the key that you created on the Access Configuration page.
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// Enable caching. Default is YES.
resolver.cacheEnable = YES;
// Enable domain resolution over IPv6 networks. Default is NO.
resolver.ipv6Enable = YES;
// Enable IP speed test. Default is NO.
resolver.speedTestEnable = YES;
// Pre-resolve domains. This automatically detects the network (IPv4-only, IPv6-only, or dual-stack) and gets a suitable IP.
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// All domains are pre-resolved.
}];
return YES;
}
2. Permitir respostas obsoletas
Antes de fazer uma solicitação de rede, recupere o IP do cache permitindo registros expirados (andExpiredIPEnabled:YES). Isso retorna um resultado imediatamente, desde que o cache esteja preenchido, mesmo que o TTL tenha expirado, alcançando resolução com latência zero.
1. Para cenários somente IPv4
//******** For IPv4-only scenarios *******
__weak typeof(self) ws = self;
// Prioritize getting the IP from the cache, allowing stale but usable records.
NSArray<NSString *> *cachedIPs = [[DNSResolver share] getIpv4ByCacheWithDomain:domain andExpiredIPEnabled:YES];
if (cachedIPs && cachedIPs.count > 0) {
NSString *ip = cachedIPs.firstObject;
NSLog(@"Fast cache hit. Domain %@ resolved to IP: %@", domain, ip);
[self requestWithIP:ip domain:domain]; // Connect directly using the IP.
} else {
// Cache miss. Perform an asynchronous resolution.
[[DNSResolver share] getIpv4DataWithDomain:domain complete:^(NSArray<NSString *> *resolvedIPs) {
if (resolvedIPs && resolvedIPs.count > 0) {
NSString *ip = resolvedIPs.firstObject;
NSLog(@"Async resolution complete. Domain %@ resolved to IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // Connect directly using the IP.
} else {
NSLog(@"Domain resolution failed. Falling back to original domain.");
[ws requestWithIP:domain domain:domain]; // Fallback: Use the original domain.
}
}];
}
2. Para cenários IPv6
//******** For dual-stack scenarios that support IPv6 *******
__weak typeof(self) ws = self;
// Prioritize getting the IP from the cache, allowing stale but usable records.
NSArray<NSString *> *cachedIPs = [[DNSResolver share] getIpsByCacheWithDomain:domain andExpiredIPEnabled:YES];
if (cachedIPs && cachedIPs.count > 0) {
NSString *ip = cachedIPs.firstObject;
NSLog(@"Fast cache hit. Domain %@ resolved to IP: %@", domain, ip);
[self requestWithIP:ip domain:domain]; // Connect directly using the IP.
} else {
// Cache miss. Perform an asynchronous resolution.
[[DNSResolver share] getIpsDataWithDomain:domain complete:^(NSArray<NSString *> *resolvedIPs) {
if (resolvedIPs && resolvedIPs.count > 0) {
NSString *ip = resolvedIPs.firstObject;
NSLog(@"Async resolution complete. Domain %@ resolved to IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // Connect directly using the IP.
} else {
NSLog(@"Domain resolution failed. Falling back to original domain.");
[ws requestWithIP:domain domain:domain]; // Fallback: Use the original domain.
}
}];
}
Observações de uso
O
pdns-sdk-ios.frameworkrequer a versão mínima do iOS 9.0.Ao fazer solicitações via HTTP, você deve definir
App Transport Security Settings->Allow Arbitrary LoadscomoYESno arquivoInfo.plist.-
Após resolver um IP via HTTPDNS, defina o cabeçalho HTTP
Hostcom o nome de domínio original ao fazer solicitações de service.Exemplo:
// `ip` is the IP address resolved from the original domain name. NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", ip]]; NSMutableURLRequest *mutableReq = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval: 10]; // Set the host. [mutableReq setValue:@"original_domain" forHTTPHeaderField:@"host"]; -
Implemente um mecanismo de fallback: se o SDK não retornar nenhum IP, faça a solicitação usando o nome de domínio original.
NSArray *array = [[DNSResolver share] getIpsByCacheWithDomain:@"original_domain" andExpiredIPEnabled:YES]; if (array && array.count > 0 && array.firstObject.length > 0) { // Replace the host in the URL with the IP and make the request. } else { // Implement fallback logic (use the original URL for the request). } Quando houver um proxy HTTP e você usar o HTTPDNS com uma URL baseada em IP, o proxy encaminhará o endereço IP como informação de Host em vez do hostname original. Isso impede que o servidor de destino processe a solicitação corretamente. Verifique se há um proxy ativado no dispositivo. Se o dispositivo estiver no modo proxy, não use o HTTPDNS para resolução de nomes de domínio.
DNS on-premises
A partir da versão 2.3.0, o SDK do HTTPDNS para iOS suporta DNS on-premises para implantações privadas.
O DNS on-premises é adequado para cenários com requisitos rigorosos de conformidade de dados e políticas de resolução personalizadas, como nos setores financeiro, governamental ou em grandes empresas. O SDK suporta quatro modos de implantação: somente nuvem pública, somente DNS on-premises e dois modos híbridos primário/backup, nos quais a nuvem pública e o DNS on-premises atuam como fallbacks mútuos.
Recursos principais
Suporte a implantação privada: Configure endpoints de servidores DNS on-premises usando endereços IPv4/IPv6 ou hostnames.
Autenticação mútua: Use seu
accessKeyIdeaccessKeySecretdedicados para assinar solicitações e proteger a comunicação.Circuit breaking e health checks: Se um nó de DNS on-premises falhar três ou mais vezes consecutivas, o circuit breaking é acionado automaticamente. Depois disso, o sistema verifica sua disponibilidade a cada minuto usando o
healthCheckDomainespecificado. O nó é reativado automaticamente após a recuperação.Controle de validação de certificado: Ative ou desative a validação de certificados TLS. Recomendamos fortemente ativá-la em ambientes de produção.
Failover inteligente: Realiza failover automático para o DNS de backup quando o DNS primário (nuvem pública ou on-premises) atinge um limiar de falhas, garantindo alta disponibilidade para resolução.
Compatibilidade total de API: As chamadas à API de resolução permanecem as mesmas, seja usando DNS de cloud pública ou DNS on-premises, sem exigir alterações na lógica do seu negócio.
Exemplos de configuração
1. Usar somente DNS de cloud pública
Este modo destina-se a usuários SaaS padrão que não implantaram um DNS on-premises.
DNSResolver *resolver = [DNSResolver share];
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccesskeySecret:@"********"];
2. Usar somente DNS on-premises (implantação privada)
Este modo destina-se a clientes que dependem inteiramente do seu DNS on-premises.
DNSResolver *resolver = [DNSResolver share];
[resolver setFusionDNSWithIPv4:@[@"1.1.X.X", @"2.2.X.X"]
IPv6:nil
Host:nil
Port:@"443"
HealthCheckDomain:@"check.example.com"
accessKeyId:@"your_fusion_ak"
accesskeySecret:@"your_fusion_sk"];
// Optional: Disable certificate validation (for test environments only).
// [resolver setEnableCertificateValidation:NO];
3. Nuvem pública como primária, on-premises como backup
Se o HTTPDNS público primário da Alibaba Cloud falhar, a resolução fará failover automaticamente para o DNS on-premises.
DNSResolver *resolver = [DNSResolver share];
// Primary: Public cloud DNS
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccesskeySecret:@"********"];
// Backup: On-premises DNS
[resolver setFusionDNSWithIPv4:@[@"1.1.X.X", @"2.2.X.X"]
IPv6:nil
Host:nil
Port:@"443"
HealthCheckDomain:@"check.example.com"
accessKeyId:@"your_fusion_ak"
accesskeySecret:@"your_fusion_sk"];
// Optional: Disable certificate validation (for test environments only).
// [resolver setEnableCertificateValidation:NO];
4. On-premises como primário, nuvem pública como backup
Se o DNS on-premises primário falhar, a resolução fará failover automaticamente para o HTTPDNS público da Alibaba Cloud.
DNSResolver *resolver = [DNSResolver share];
// Primary: On-premises DNS
[resolver setFusionDNSWithIPv4:@[@"1.1.X.X", @"2.2.X.X"]
IPv6:nil
Host:nil
Port:@"443"
HealthCheckDomain:@"check.example.com"
accessKeyId:@"your_fusion_ak"
accesskeySecret:@"your_fusion_sk"];
// Optional: Disable certificate validation (for test environments only).
// [resolver setEnableCertificateValidation:NO];
// Backup: Public cloud DNS
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccesskeySecret:@"********"];
Novas APIs de service
O SDK fornece três APIs principais para configuração de DNS on-premises, controle de políticas de segurança e failover automático primário/backup.
1. Configuração de DNS on-premises
/** This is related to on-premises DNS for private deployments. Do not call this method if you only use public DNS.
*
* Sets the on-premises DNS server address and authentication information.
* Use this interface to pass your private DNS server's address and authentication credentials.
* The SDK will use this information to initiate requests.
* @param ipv4 An array of IPv4 addresses (can be nil).
* @param ipv6 An array of IPv6 addresses (can be nil).
* @param host An array of hostnames (can be nil).
* @param port The service port (for example, @"443"). If nil, the default port is used.
* @param healthCheckDomain The domain for health checks after a circuit break. If a resolution service fails more than three consecutive times, the circuit is tripped, and the service IP enters a healthCheck state. Subsequent requests will not use this service. A timer then probes this healthCheckDomain every minute to check if the service is available. If a probe succeeds, the service state is restored to alive and can receive requests again.
* @param accessKeyId Your private accessKeyId for authentication.
* @param accesskeySecret Your private accesskeySecret for authentication.
*/
- (void)setFusionDNSWithIPv4:(NSArray<NSString *> * _Nullable)ipv4
IPv6:(NSArray<NSString *> * _Nullable)ipv6
Host:(NSArray<NSString *> * _Nullable)host
Port:(NSString * _Nullable)port
HealthCheckDomain:(NSString * _Nonnull)healthCheckDomain
accessKeyId:(NSString * _Nonnull)accessKeyId
accesskeySecret:(NSString * _Nonnull)accesskeySecret;
2. Validação de certificado TLS
/** This is related to on-premises DNS for private deployments. Do not call this method if you only use public DNS.
*
* Enable or disable certificate validation for on-premises DNS. The default is YES. If your server is not configured with a domain or IP certificate, you can set this to NO for testing. For production environments, set this to YES to avoid security risks.
* @param enable YES to enable (default), NO to disable.
*/
- (void)setEnableCertificateValidation:(BOOL)enable;
3. Limiar de failover automático
/** When both public cloud DNS and on-premises DNS are configured, this sets the number of primary DNS failures that trigger an automatic failover to the backup DNS. If only one type of DNS is configured, do not call this method.
*
* Sets the number of primary DNS failures before automatically failing over to the backup DNS. If only one type of DNS is configured, do not call this method.
* @param fallbackThreshold The number of failures. The default is 4 when public cloud DNS is primary, and 2 when on-premises DNS is primary.
* The valid range is [0-4]. A value of 0 means failover occurs immediately. The maximum is 4.
*/
- (void)setFallbackThreshold:(NSInteger)fallbackThreshold;