アプリに HTTPDNS iOS SDK を統合することで、内蔵キャッシングによる信頼性の高いドメイン名解決が可能になります。
概要
iOS SDK は、HTTPDNS の DoH JSON API をカプセル化し、iOS アプリ用の名前解決 API と、TTL および LRU ポリシーに基づく効率的なドメイン名のキャッシュ機能を提供します。iOS アプリに HTTPDNS を統合することで、名前解決の異常を修正し、正確で低コストの解決スケジューリングを実現します。
また、iOS 14 のネイティブ暗号化 DNS ソリューションを使用して、HTTPDNS をデフォルトの暗号化された DNS リゾルバーとして設定することもできます。
主なメリット:
使いやすさ:
最小限のコードで HTTPDNS をアプリに統合できます。
ゼロレイテンシー:
内部の LRU キャッシュが解決済みの IP をローカルに保存し、期限切れのエントリを事前に更新することで、ゼロレイテンシーの名前解決を実現します。
Objective-C サンプルプロジェクト: alidns_ios_demo のソースコード。
Swift サンプルプロジェクト: DNSResolverSwiftDemo のソースコード。
SDK 統合
SDK のインポート
CocoaPods
Podfile にリポジトリの場所を指定します。マスターリポジトリを必ず含めてください。
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/aliyun/aliyun-specs.git'プロジェクトターゲットに依存関係を追加します:
pod 'AlicloudPDNS'
手動
SDK Download から iOS SDK をダウンロードします。
SDK フレームワーク
pdns-sdk-ios.frameworkを取得したら、プロジェクトに手動で追加します。必要なシステムライブラリをインポートします:
Foundation.framework
SystemConfiguration.framework
CoreFoundation.framework
CoreTelephony.framework
プロジェクトのビルド設定で、他のリンカーフラグに -ObjC フラグを追加します。
SDK の初期化
初期化の前に、コンソールでアプリケーションを登録し、アカウント ID と AccessKey 認証情報を取得します。
名前解決の失敗を防ぐため、アプリケーションのライフサイクルの、できるだけ早い段階で SDK を初期化してください。
application:didFinishLaunchingWithOptions: メソッドで SDK を初期化します。
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": アスタリスクを、コンソールのアクセス構成ページにあるアカウント ID に置き換えます。
// andAccessKeyId:@"********": アスタリスクを、アクセス構成ページで作成したキーの AccessKey ID に置き換えます。
// andAccesskeySecret:@"********": アスタリスクを、アクセス構成ページで作成したキーの AccesskeySecret に置き換えます。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// キャッシュの自動更新の対象となるドメインを指定します。配列には最大 10 個のドメインを含めることができます。
[resolver setKeepAliveDomains:@[@"your_domain_1", @"your_domain_2"]];
// 後で使用する予定のドメインを事前名前解決します。
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインの事前名前解決が完了しました。
}];API リファレンス
共通設定
1. アカウント ID と認証
必須です。コンソールは、アプリケーションを登録すると一意の アカウント ID を生成します。認証に使用する AccessKey を作成するには、アクセスキーペアを作成し、次のように設定します:
// setAccountId:@"******":アスタリスクを、コンソールのアクセス構成ページにあるアカウント ID に置き換えます。
// andAccessKeyId:@"********":アスタリスクを、アクセス構成ページで作成したキーの AccessKey ID に置き換えます。
// andAccesskeySecret:@"********":アスタリスクを、アクセス構成ページで作成したキーの AccessKey Secret に置き換えます。
[[DNSResolver share] setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];本番リリースでは、実行中のアプリケーションが生成するログなどのデータにアカウント ID、AccessKey ID、または AccessKey Secret が出力されないよう、SDK のデバッグログを無効にしてください。
サンプルコードでは説明のため、アカウント ID、AccessKey ID、AccessKey Secret を直接渡しています。これらの認証情報は課金に使用されます。悪意のある逆コンパイルによる漏えいを防ぐため、本番アプリケーションではプレーンテキストの認証情報をハードコードしないでください。代わりに、必要なときだけエンコードまたは暗号化した値をデコードまたは復号してください。また、アプリケーションのコードを難読化し、強化することを推奨します。そうしない場合、アカウント ID、AccessKey ID、AccessKey Secret が侵害される可能性があります。
2. 名前解決プロトコルの設定
scheme プロパティを使用して、名前解決プロトコル (HTTP または HTTPS) を設定します。
SDK は、セキュリティがより高いため、デフォルトで HTTPS プロトコルを使用することを推奨します。 HTTPDNS は、名前解決リクエスト数に基づいて課金されます。HTTPS リクエストの料金は HTTP リクエストの 5 倍です。ビジネス要件に基づいて scheme タイプを選択してください。 プロパティは次のように設定します:
[DNSResolver share].scheme = DNSResolverSchemeHttps;3. キャッシュの有効化または無効化
有効にすると、名前解決結果がローカルにキャッシュされ、以降の参照ではキャッシュから即座に結果が返されます。
キャッシュはデフォルトで有効です。無効にするには、次のコードを使用します:
[DNSResolver share].cacheEnable=NO;4. ドメインのキープアライブキャッシュの設定
有効にすると、SDK は指定したドメインのキャッシュエントリが期限切れになる前に、事前に更新します。これによりデータは最新の状態に保たれますが、名前解決リクエスト数とネットワークトラフィックが増加します。この機能を使用しない場合、キャッシュの更新は名前解決メソッドが呼び出されたときにのみ行われます。
// 配列には最大 10 個のドメインを指定できます。
[[DNSResolver share] setKeepAliveDomains:@[@"www.taobao.com",@"www.aliyun.com"]];メリット:
レコードが迅速に更新されます (TTL の期限切れ前)。
事前解決と組み合わせると、初回の名前解決レイテンシーを 0 ms に低減できます。
デメリット:レコードの TTL の 75% の時点で再リクエストが発生するため、追加コストがかかります。
5. 事前解決
アプリ起動時にドメインを事前解決すると、以降の参照ではキャッシュがヒットし、ほぼゼロレイテンシーで結果を取得できます。
コード例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// アプリケーション起動後のカスタマイズポイント。
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******":アスタリスクをコンソールのアクセス構成ページのアカウント ID に置き換えます。
// andAccessKeyId:@"********":アスタリスクをアクセス構成ページで作成したキーの AccessKey ID に置き換えます。
// andAccesskeySecret:@"********":アスタリスクをアクセス構成ページで作成したキーの AccessKey Secret に置き換えます。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
resolver.cacheEnable = YES;
// 後で使用する可能性のあるドメインを事前解決します。
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインが事前解決されました。
}];
return YES;
}詳細設定
1. サーバー側 IPv6 アクセスの有効化
HTTPDNS サービスは、IPv4 と IPv6 の デュアルスタック アクセスをサポートしています。デフォルトでは、SDK は IPv4 を使用します。
IPv6 を使用するには、ネットワークが IPv6 をサポートしていることを確認し、この機能を有効にします:
[DNSResolver share].ipv6Enable = YES;2. ショートモード
HTTPDNS DoH JSON API は、完全な JSON または簡略化された IP 配列のいずれかを返します。SDK はデフォルトで完全な JSON を使用します。
簡略化された IP 配列形式を使用するには、次のように設定します:
[DNSResolver share].shortEnable = YES;3. キャッシュサイズの設定
キャッシュが有効な場合、キャッシュするドメイン数をカスタマイズできます。サポートされる範囲は 100~500 です。
デフォルトのキャッシュサイズは 100 ドメインです。カスタムのキャッシュサイズを設定するには、cacheCountLimit プロパティを使用します:
[DNSResolver share].cacheCountLimit = 200;4. IP 速度テストの有効化または無効化
IP 速度テストを有効にすると、名前解決結果がレイテンシー順に並べ替えられ、最も速い IP が最初に返されます。
SDK v2.3.1 以降では、IP 速度テストはデフォルトで有効 (YES) です。以前のバージョンでは、デフォルトで無効 (NO) です。この機能を明示的に設定するには、次のコードを使用します:
[DNSResolver share].speedTestEnable=YES;5. IP 速度テスト方法の設定
プロービング方法を設定します。ICMP プロービングの場合は 0、ソケットプロービングの場合は対象ポートのポート番号 (80、443 など) を設定します。
SDK v2.3.1 以降では、デフォルトポートは 80 です。以前のバージョンでは、デフォルトポートは 443 です。
[DNSResolver share].speedPort = 80;6. IPv6 速度テストのハンディキャップの設定 (v2.3.1 以降でサポート)
IPv6 速度テストのハンディキャップをミリ秒単位で設定します。名前解決結果に IPv4 アドレスと IPv6 アドレスの両方が含まれる場合、SDK は IPv6 の計測レイテンシーからこのハンディキャップを差し引いてから、IPv4 のレイテンシーと比較します。その差がハンディキャップの範囲内であれば、IPv6 アドレスがわずかに遅い場合でも IPv6 アドレスが優先されます。有効範囲は 0~1000 です。この設定は、IP 速度テストが有効な場合にのみ有効になります。
デフォルト値は 0 で、この場合ハンディキャップは無効になります。カスタムのハンディキャップを設定するには、次のコードを使用します:
[DNSResolver share].speedTestIpv6PreferMs = 0;7. ISP 固有のドメイン名キャッシュの有効化または無効化
有効にすると、キャッシュエントリは ISP ネットワークごとに分離されます。無効にすると、すべてのネットワークで 1 つのキャッシュを共有します。
ISP 固有のドメイン名キャッシュはデフォルトで有効です。
[DNSResolver share].ispEnable = YES;8. ネガティブキャッシュの最大 TTL の設定
名前解決に失敗した結果を保存するネガティブキャッシュの最大 TTL を設定します。
デフォルト値は 30 秒です。ネガティブキャッシュの最大 TTL をカスタマイズするには、次のコードを使用します:
[DNSResolver share].maxNegativeCache = 30;9. 最大キャッシュ TTL の設定
サーバーから提供される TTL 値にかかわらず、エントリの有効期間に上限を設ける最大キャッシュ TTL を設定します。
デフォルト値は 3600 秒です。最大キャッシュ TTL をカスタマイズするには、次のコードを使用します:
[DNSResolver share].maxCacheTTL= 3600;10. イミュータブルキャッシュの有効化
[DNSResolver share].immutableCacheEnable = NO; // デフォルトではイミュータブルキャッシュは無効です。SDK は 3 つのキャッシュ更新メカニズムを提供します:
イミュータブルキャッシュ:この機能を有効にすると、アプリケーションの実行中はキャッシュが常に有効として扱われます。SDK は期限切れチェックと更新をスキップするため、名前解決リクエスト数を最小限に抑えられます。
有効にするには、次を呼び出します:
[DNSResolver share].immutableCacheEnable = YESアクティブなキャッシュ更新:キャッシュされた名前解決結果を最新の状態に保ちます。ドメインの権威レコードが変更された場合でも、SDK がキャッシュ済みレコードを更新する間、リクエストは低レイテンシーのキャッシュヒットの恩恵を受けられます。配列は最大 10 個のドメインに制限されます。
有効にするには、次を呼び出します:
[[DNSResolver share] setKeepAliveDomains:@[@"your_domain_1",@"your_domain_2"]]パッシブなキャッシュ更新:名前解決結果を取得するために次の 2 つのメソッドのいずれかを呼び出すと、キャッシュがパッシブに更新されます:
- (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))completeメソッドは、ドメインの IPv4 アドレス配列を取得します。キャッシュが空でなく、エントリが TTL 内であれば、キャッシュ結果を直ちに返します。それ以外の場合は、ネットワーク経由で最新の結果を取得して返し、キャッシュを更新します。このメソッドは、高い正確性が求められるシナリオで使用します。- (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enableメソッドは、キャッシュから IPv4 の名前解決結果を取得します。このメソッドの動作は、enableパラメータに依存します。パラメータの説明:
enableがYESの場合、キャッシュが期限切れでも古いレコードを返します (キャッシュが空の場合はnil)。その後、キャッシュを非同期に更新します。NOの場合、キャッシュが期限切れまたは空のときはnilを返し、その後、キャッシュを非同期に更新します。
11. タイムアウト
timeout プロパティは、名前解決リクエストの timeout を設定します。デフォルト: 3 秒。推奨範囲: 2 秒~5 秒です。
12. 同時名前解決リクエストの最大数の設定 (v2.3.1 以降でサポート)
SDK が送信する同時 DNS 名前解決リクエストの最大数を設定します。有効範囲は 1~50 です。デフォルト値は 10 です。上限をカスタマイズするには、次のコードを使用します:
[DNSResolver share].maxConcurrentResolveCount = 10;サービス API
コード例:
/// ドメイン情報を事前名前解決します。アプリの起動時にこのメソッドを呼び出します。結果をキャッシュに保存して、後続の名前解決を高速化します。
/// ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) を自動的に検出し、現在のネットワークに適した名前解決を実行します。
/// @param domainArray ドメイン名の配列。
/// @param complete 名前解決完了後に実行されるコールバック。
- (void)preloadDomains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// ドメインの IP アドレスの配列を取得します。このメソッドは、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) を自動的に検出し、適切な IP を取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。キャッシングが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete すべての IP アドレスを返すコールバック。
- (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// 待機せずに、キャッシュから直接 IP アドレスの配列を取得します。このメソッドは、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) を自動的に検出します。
/// キャッシュが空の場合は nil を返します。キャッシュが空でなく、 `enable` が YES の場合、キャッシュされたデータを返します。データが期限切れの場合、非同期でキャッシュを更新します。キャッシュが空でなく、 `enable` が NO の場合、期限切れのエントリについては nil を返し、非同期でキャッシュを更新します。
/// @param domain ドメイン名。
/// @param enable 期限切れの IP アドレスを返すかどうかを指定します。
- (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// ドメインの IPv4 情報オブジェクトの配列を取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で情報を取得します。キャッシングが無効な場合、常にネットワーク経由で情報を取得します。
/// @param domain ドメイン名。
/// @param complete すべてのドメイン情報オブジェクトを返すコールバック。
- (void)getIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete;
/// ドメインの IPv6 情報オブジェクトの配列を取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で情報を取得します。キャッシングが無効な場合、常にネットワーク経由で情報を取得します。
/// @param domain ドメイン名。
/// @param complete すべてのドメイン情報オブジェクトを返すコールバック。
- (void)getIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete;
/// ドメインのランダムな IPv4 情報オブジェクトを取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で情報を取得します。キャッシングが無効な場合、常にネットワーク経由で情報を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムなドメイン情報オブジェクトを 1 つ返すコールバック。
- (void)getRandomIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete;
/// ドメインのランダムな IPv6 情報オブジェクトを取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で情報を取得します。キャッシングが無効な場合、常にネットワーク経由で情報を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムなドメイン情報オブジェクトを 1 つ返すコールバック。
- (void)getRandomIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete;
/// ドメインの IPv4 アドレスの配列を取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。キャッシングが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete すべての IP アドレスを返すコールバック。
- (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// ドメインの IPv6 アドレスの配列を取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。キャッシングが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete すべての IP アドレスを返すコールバック。
- (void)getIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;
/// ドメインのランダムな IPv4 アドレスを取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。キャッシングが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムな IP アドレスを 1 つ返すコールバック。
- (void)getRandomIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete;
/// ドメインのランダムな IPv6 アドレスを取得します。
/// キャッシングが有効な場合、最初にキャッシュからデータを返します。キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。キャッシングが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムな IP アドレスを 1 つ返すコールバック。
- (void)getRandomIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete;
/// ドメインの IPv4 情報を事前名前解決します。アプリの起動時にこのメソッドを呼び出します。結果をキャッシュに保存して、後続の名前解決を高速化します。
/// @param domainArray ドメイン名の配列。
/// @param complete 名前解決完了後に実行されるコールバック。
- (void)preloadIpv4Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// ドメインの IPv6 情報を事前名前解決します。アプリの起動時にこのメソッドを呼び出します。結果をキャッシュに保存して、後続の名前解決を高速化します。
/// @param domainArray ドメイン名の配列。
/// @param complete 名前解決完了後に実行されるコールバック。
- (void)preloadIpv6Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete;
/// 待機せずに、キャッシュから直接 IPv4 アドレスの配列を取得します。
/// キャッシュが空の場合は nil を返します。キャッシュが空でなく、 `enable` が YES の場合、キャッシュされたデータを返します。データが期限切れの場合、非同期でキャッシュを更新します。キャッシュが空でなく、 `enable` が NO の場合、期限切れのエントリについては nil を返し、非同期でキャッシュを更新します。
/// @param domain ドメイン名。
/// @param enable 期限切れの IP アドレスを返すかどうかを指定します。
- (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// 待機せずに、キャッシュから直接 IPv6 アドレスの配列を取得します。
/// キャッシュが空の場合は nil を返します。キャッシュが空でなく、 `enable` が YES の場合、キャッシュされたデータを返します。データが期限切れの場合、非同期でキャッシュを更新します。キャッシュが空でなく、 `enable` が NO の場合、期限切れのエントリについては nil を返し、非同期でキャッシュを更新します。
/// @param domain ドメイン名。
/// @param enable 期限切れの IP アドレスを返すかどうかを指定します。
- (NSArray<NSString *> *)getIpv6ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
/// リクエスト統計を収集します。
-(NSArray *)getRequestReportInfo;API の使用例
1. 基本情報の設定
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// アプリケーション起動後のカスタマイズのためのオーバーライドポイント。
// 初期化メソッド
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******":アスタリスクを、コンソールの [アクセス構成] ページのアカウント ID に置き換えます。
// andAccessKeyId:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey ID に置き換えます。
// andAccesskeySecret:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey Secret に置き換えます。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// キャッシュの自動更新のためにドメインを指定します。 配列には最大 10 個のドメインを含めることができます。
[resolver setKeepAliveDomains:@[@"your_domain_1",@"your_domain_2"]];
// ドメインを事前解決して結果を取得し、キャッシュに保存します。
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインが事前解決されます。
}];
return YES;
}2. 名前解決 API の使用
SDK は、DNSResolver.h に複数の解決メソッドを提供します。 次の例では、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) に自動的に適応するメソッドを使用します。
API 宣言:
/// ドメインの IP アドレスの配列を取得します。 このメソッドは、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) に自動的に適応します。
/// キャッシュが有効な場合、最初にキャッシュからデータを返します。 キャッシュが空または期限切れの場合、ネットワーク経由で IP を取得します。 キャッシュが無効な場合、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete すべての IP アドレスを返すコールバック。
- (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;API 呼び出しの例:
[[DNSResolver share] getIpsDataWithDomain:@"www.taobao.com" complete:^(NSArray<NSString *> *dataArray) {
// dataArray は www.taobao.com の IP アドレスの配列です。
if (dataArray.count > 0) {
//TODO: IP アドレスを使用して URL 接続を行います。
}
}];3. キャッシュから直接解決結果を取得
API 宣言:
/// 待機せずにキャッシュから直接 IP アドレスの配列を取得します。 このメソッドは、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) に自動的に適応します。
/// キャッシュが空の場合は nil を返します。 キャッシュにデータがあり、`enable` が YES に設定されている場合、キャッシュされたデータを返します。 データが期限切れの場合、非同期でキャッシュを更新します。 キャッシュにデータがあり、`enable` が NO に設定されている場合、期限切れのエントリに対しては nil を返し、非同期でキャッシュを更新します。
/// @param domain ドメイン名。
/// @param enable 期限切れの IP アドレスを返すかどうかを指定します。
- (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;API 呼び出しの例:
NSArray *result = [[DNSResolver share] getIpsByCacheWithDomain:@"your_domain" andExpiredIPEnabled:YES];
// キャッシュされた結果を使用します。
if (result.count > 0) {
//TODO: IP アドレスを使用して URL 接続を行います。
}注:キャッシュから直接結果を取得すると高速ですが、キャッシュが空の場合、またはキャッシュの有効期限が切れており、かつ enable が NO に設定されている場合、メソッドは nil を返します。
4. キャッシュのクリア
API 宣言:
/// `hostArray` は、キャッシュからクリアするホスト名の配列です。 すべてのデータをクリアするには、nil または空の配列を渡します。
-(void)clearHostCache:(NSArray <NSString *>*)hostArray;API 呼び出しの例:
[[DNSResolver share] clearHostCache:@[@"domain1", @"domain2"]];5. 統計の収集
API 宣言:
/// リクエスト統計を収集します。
-(NSArray *)getRequestReportInfo;API 呼び出しの例:
NSArray *array = [[DNSResolver share] getRequestReportInfo];データ形式:
(
{
avgRtt = "1"; // 平均名前解決時間 (ms)
cacheDnsNum = 0; // キャッシュヒット数
domain = "www.taobao.com"; // 解決されたドメイン
gobackLocaldnsNum = 0; // ローカル DNS へのフォールバック数
localErro = 0; // ローカル DNS 解決の失敗数
maxRtt = "60"; // 最大名前解決時間 (ms)
noPermissionErro = 0; // 認証失敗数
noResponseErro = 0; // 無応答エラー数
requestPDnsNum = 1; // 再帰クエリ数
sp = "China Mobile"; // ISP 名
successNum = 1; // 解決成功数
timeoutErro = 0; // ネットワークタイムアウトエラー数
type = 28; // IP タイプ (1: IPv4、28: IPv6)
urlParameterErro = 0; // URL パラメーター形式エラー数
urlPathErro = 0; // URL パスエラー数
}
......
);名前解決のベストプラクティス
最適なパフォーマンスを得るには、事前解決と stale-while-revalidate を組み合わせます。
起動時に主要なドメインを事前解決してキャッシュにデータを投入すると、後続のルックアップでネットワークラウンドトリップが回避され、ほぼゼロレイテンシーの解決が実現します。
その後、組み込みキャッシュが後続のリクエストにメモリから直接応答します。
1. 事前解決
キャッシングを有効にし、アプリの起動時に主要なドメインを事前解決します。
AppDelegate の application:didFinishLaunchingWithOptions: メソッドで、アプリケーションで使用されるドメイン名を事前解決し、結果をローカルメモリにキャッシュします。
1. IPv4 のみの場合
//******** IPv4 のみの場合 *******
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******":アスタリスクを、コンソールの [アクセス構成] ページのアカウント ID に置き換えてください。
// andAccessKeyId:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey ID に置き換えてください。
// andAccesskeySecret:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey Secret に置き換えてください。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// キャッシングを有効にします。 デフォルトは YES です。
resolver.cacheEnable = YES;
// 今後使用するドメインの IPv4 情報を事前解決します。
[resolver preloadIpv4Domains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインの事前解決が完了します。
}];
return YES;
}2. IPv6 の場合
//******** IPv6 対応のデュアルスタックシナリオの場合 *******
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******":アスタリスクを、コンソールの [アクセス構成] ページのアカウント ID に置き換えてください。
// andAccessKeyId:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey ID に置き換えてください。
// andAccesskeySecret:@"********":アスタリスクを、[アクセス構成] ページで作成したキーの AccessKey Secret に置き換えてください。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];
// キャッシングを有効にします。 デフォルトは YES です。
resolver.cacheEnable = YES;
// IPv6 ネットワーク経由でのドメイン解決を有効にします。 デフォルトは NO です。
resolver.ipv6Enable = YES;
// IP スピードテストを有効にします。 デフォルトは NO です。
resolver.speedTestEnable = YES;
// ドメインを事前解決します。 これにより、ネットワーク (IPv4 のみ、IPv6 のみ、またはデュアルスタック) が自動的に検出され、適切な IP を取得します。
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインの事前解決が完了します。
}];
return YES;
}2. ステイル応答の許可
ネットワークリクエストを行う前に、期限切れのレコードを許可して (andExpiredIPEnabled:YES) キャッシュから IP を取得します。これにより、TTL が期限切れであっても、キャッシュにデータがあれば結果が即座に返されることで、ゼロレイテンシーの解決が実現します。
1. IPv4 のみの場合
//******** IPv4 のみの場合 *******
__weak typeof(self) ws = self;
// キャッシュからの IP 取得を優先し、ステイルながらも利用可能なレコードを許可します。
NSArray<NSString *> *cachedIPs = [[DNSResolver share] getIpv4ByCacheWithDomain:domain andExpiredIPEnabled:YES];
if (cachedIPs && cachedIPs.count > 0) {
NSString *ip = cachedIPs.firstObject;
NSLog(@"高速キャッシュヒット。 ドメイン: %@, 解決された IP: %@", domain, ip);
[self requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
// キャッシュミス。 非同期解決を実行します。
[[DNSResolver share] getIpv4DataWithDomain:domain complete:^(NSArray<NSString *> *resolvedIPs) {
if (resolvedIPs && resolvedIPs.count > 0) {
NSString *ip = resolvedIPs.firstObject;
NSLog(@"非同期解決が完了。 ドメイン: %@, 解決された IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
NSLog(@"ドメイン解決に失敗しました。 オリジナルのドメインにフォールバックします。");
[ws requestWithIP:domain domain:domain]; // フォールバック:元のドメインを使用します。
}
}];
}2. IPv6 の場合
//******** IPv6 対応のデュアルスタックシナリオの場合 *******
__weak typeof(self) ws = self;
// キャッシュからの IP 取得を優先し、ステイルながらも利用可能なレコードを許可します。
NSArray<NSString *> *cachedIPs = [[DNSResolver share] getIpsByCacheWithDomain:domain andExpiredIPEnabled:YES];
if (cachedIPs && cachedIPs.count > 0) {
NSString *ip = cachedIPs.firstObject;
NSLog(@"高速キャッシュヒット。 ドメイン: %@, 解決された IP: %@", domain, ip);
[self requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
// キャッシュミス。 非同期解決を実行します。
[[DNSResolver share] getIpsDataWithDomain:domain complete:^(NSArray<NSString *> *resolvedIPs) {
if (resolvedIPs && resolvedIPs.count > 0) {
NSString *ip = resolvedIPs.firstObject;
NSLog(@"非同期解決が完了。 ドメイン: %@, 解決された IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
NSLog(@"ドメイン解決に失敗しました。 オリジナルのドメインにフォールバックします。");
[ws requestWithIP:domain domain:domain]; // フォールバック:元のドメインを使用します。
}
}];
}Usage notes
The
pdns-sdk-ios.frameworkrequires a minimum iOS version of 9.0.When you make requests over HTTP, you must set
App Transport Security Settings->Allow Arbitrary LoadstoYESin yourInfo.plistfile.After resolving an IP from HTTPDNS, set the
HostHTTP header to the original domain name when making service requests.Example:
// `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"];Implement a fallback mechanism: if the SDK returns no IP, make the request using the original domain name.
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). }When an HTTP proxy is present and you use HTTPDNS with an IP-based URL, the proxy forwards the IP address as the Host information instead of the original hostname. This prevents the target server from processing the request correctly. Check whether a proxy is enabled on the device. If your device is in proxy mode, do not use HTTPDNS for domain name resolution.
オンプレミス DNS
v2.3.0 以降、HTTPDNS iOS SDK はプライベートデプロイメント向けにオンプレミス DNS をサポートしています。
オンプレミス DNS は、金融、政府機関、大企業など、データコンプライアンス要件が厳しく、名前解決ポリシーのカスタマイズが必要なシナリオに適しています。SDK は 4 つのデプロイメントモード (パブリッククラウドのみ、オンプレミス DNS のみ、パブリッククラウドとオンプレミス DNS が相互にフォールバックとして機能するプライマリ/バックアップのハイブリッドモード 2 種類) をサポートします。
コア機能
プライベートデプロイメントのサポート: IPv4/IPv6 アドレスまたはホスト名を使用して、オンプレミス DNS サーバーのエンドポイントを構成します。
相互認証: 専用の
accessKeyIdとaccessKeySecretを使用してリクエストに署名し、通信を保護します。サーキットブレーキングとヘルスチェック: オンプレミス DNS ノードで 3 回以上連続して障害が発生すると、サーキットブレーキングが自動的にトリガーされます。その後、システムは指定された
healthCheckDomainを使用して 1 分ごとに可用性をチェックします。ノードは、復旧後に自動的に再度有効になります。証明書検証の制御: TLS 証明書検証を有効または無効にできます。本番環境では有効にすることを強く推奨します。
スマートフェールオーバー:プライマリ DNS (パブリッククラウドまたはオンプレミス) が失敗しきい値に達すると、バックアップ DNS に自動的にフェールオーバーし、名前解決の高可用性を確保します。
シームレスな API 互換性:パブリッククラウド DNS とオンプレミス DNS のどちらを使用しても、名前解決 API 呼び出しは同一であり、ビジネスロジックの変更は不要です。
構成例
1. パブリッククラウド DNS のみの使用
このモードは、オンプレミス DNS をデプロイしていない標準 SaaS ユーザー向けです。
DNSResolver *resolver = [DNSResolver share];
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccessKeySecret:@"********"];2. オンプレミス DNS のみの使用 (プライベートデプロイメント)
このモードは、オンプレミス DNS に完全に依存するお客様向けです。
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"];
// オプション: 証明書検証を無効にします (テスト環境のみ)。
// [resolver setEnableCertificateValidation:NO];3. パブリッククラウド (プライマリ) とオンプレミス (バックアップ) の併用
プライマリの Alibaba Cloud パブリック HTTPDNS が失敗すると、名前解決は自動的にオンプレミス DNS にフェイルオーバーします。
DNSResolver *resolver = [DNSResolver share];
// プライマリ: パブリッククラウド DNS
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccessKeySecret:@"********"];
// バックアップ: オンプレミス 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"];
// オプション: 証明書検証を無効にします (テスト環境のみ)。
// [resolver setEnableCertificateValidation:NO];4. オンプレミス (プライマリ) とパブリッククラウド (バックアップ) の併用
プライマリのオンプレミス DNS が失敗すると、名前解決は自動的に Alibaba Cloud パブリック HTTPDNS にフェイルオーバーします。
DNSResolver *resolver = [DNSResolver share];
// プライマリ: オンプレミス 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"];
// オプション: 証明書検証を無効にします (テスト環境のみ)。
// [resolver setEnableCertificateValidation:NO];
// バックアップ: パブリッククラウド DNS
[resolver setAccountId:@"******"
andAccessKeyId:@"********"
andAccessKeySecret:@"********"];新しいサービス API
SDK は、オンプレミス DNS 構成、TLS 証明書検証、および自動プライマリ/バックアップフェイルオーバー用の 3 つのコア API を提供します。
1. オンプレミス DNS 構成
/** これはプライベートデプロイメント用のオンプレミス DNS に関連します。パブリック DNS のみを使用する場合は、このメソッドを呼び出さないでください。
*
* オンプレミス DNS サーバーのアドレスと認証情報を設定します。
* このインターフェースを使用して、プライベート DNS サーバーのアドレスと認証情報を渡します。
* SDK はこの情報を使用してリクエストを開始します。
* @param ipv4 IPv4 アドレスの配列 (nil 可)。
* @param ipv6 IPv6 アドレスの配列 (nil 可)。
* @param host ホスト名の配列 (nil 可)。
* @param port サービスポート (例: @"443")。nil の場合、デフォルトポートが使用されます。
* @param healthCheckDomain サーキットブレーク後のヘルスチェック用ドメイン。名前解決サービスが 3 回を超えて連続して失敗すると、サーキットブレーカーが作動し、サービス IP は healthCheck 状態に移行します。その後のリクエストはこのサービスを使用しません。タイマーは、この healthCheckDomain を毎分プローブして、サービスが利用可能かどうかを確認します。プローブが成功すると、サービスの状態は alive に復元され、再びリクエストを受信できるようになります。
* @param accessKeyId 認証用のプライベート accessKeyId。
* @param accesskeySecret 認証用のプライベート accesskeySecret。
*/
- (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. TLS 証明書検証
/** これはプライベートデプロイメント用のオンプレミス DNS に関連します。パブリック DNS のみを使用する場合は、このメソッドを呼び出さないでください。
*
* オンプレミス DNS の証明書検証を有効または無効にします。デフォルトは YES です。サーバーにドメインまたは IP 証明書が設定されていない場合、テスト用に NO に設定できます。本番環境では、セキュリティリスクを回避するために YES に設定してください。
* @param enable YES で有効 (デフォルト)、NO で無効。
*/
- (void)setEnableCertificateValidation:(BOOL)enable;3. 自動フェイルオーバーしきい値
/** パブリック クラウド DNS とオンプレミス DNS の両方が構成されている場合、バックアップ DNS への自動フェイルオーバーをトリガーするプライマリ DNS の障害回数を設定します。1 種類の DNS のみが構成されている場合は、このメソッドを呼び出さないでください。
*
* バックアップ DNS に自動的にフェイルオーバーする前のプライマリ DNS の障害回数を設定します。1 種類の DNS のみが構成されている場合は、このメソッドを呼び出さないでください。
* @param fallbackThreshold 障害回数。パブリック クラウド DNS がプライマリの場合、デフォルトは 4 です。オンプレミス DNS がプライマリの場合、デフォルトは 2 です。
* 有効範囲は [0-4] です。値が 0 の場合は、フェイルオーバーが即座に発生することを意味します。最大値は 4 です。
*/
- (void)setFallbackThreshold:(NSInteger)fallbackThreshold;