HTTPDNS iOS SDK をアプリに統合することで、組み込みのキャッシングによる信頼性の高い名前解決が可能になります。
概要
iOS SDK は、 HTTPDNS の DoH JSON API をカプセル化し、 iOS アプリでの 名前解決 のための API と、TTL および LRU ポリシーに基づく効率的な ドメイン名のキャッシュ を提供します。 この SDK を使用すると、開発者は HTTPDNS を iOS アプリに簡単に統合して、名前解決の問題を解決し、正確かつ低コストな名前解決を実現できます。
また、 iOS 14 ネイティブ暗号化 DNS ソリューションを使用して、 HTTPDNS をデフォルトの暗号化 DNS リゾルバとして設定することもできます。
主なメリット:
-
使いやすさ:
最小限のコードで HTTPDNS をアプリに統合できます。
-
ゼロレイテンシー:
内部の LRU キャッシュが、解決済みの IP をローカルに保存し、期限切れのエントリを事前に更新することで、ゼロレイテンシーの名前解決が可能になります。
Objective-C サンプルプロジェクト: alidns_ios_demo サンプルプロジェクトのソースコード。
Swift サンプルプロジェクト: DNSResolverSwiftDemo サンプルプロジェクトのソースコード。
SDK の統合
SDK のインポート
CocoaPods
-
Podfile でリポジトリの場所を指定します。master リポジトリを必ず含めてください。
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 とアクセスキー認証情報を取得します。
名前解決の失敗を防ぐため、アプリケーションのライフサイクルのできるだけ早い段階で SDK を初期化してください。
application:didFinishLaunchingWithOptions: メソッドで SDK を初期化します。
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******": アスタリスクを、コンソールのアクセス設定ページにあるアカウント ID に置き換えます。
// andAccessKeyId:@"********": アスタリスクを、コンソールのアクセス設定ページで作成したキーのアクセスキー ID に置き換えます。
// andAccessKeySecret:@"********": アスタリスクを、コンソールのアクセス設定ページで作成したキーの AccessKey シークレットに置き換えます。
[resolver setAccountId:@"******" andAccessKeyId:@"********" andAccessKeySecret:@"********"];
// キャッシュの自動更新の対象ドメインを指定します。配列には最大 10 個のドメインを含めることができます。
[resolver setKeepAliveDomains:@[@"your_domain_1", @"your_domain_2"]];
// 後ほど使用するドメインを事前解決します。
[resolver preloadDomains:@[@"domain1", @"domain2", @"domain3"] complete:^{
// すべてのドメインが事前解決されました。
}];
API リファレンス
共通設定
1. アカウント ID と認証
必須です。アプリを登録すると、コンソールが一意な アカウント ID を生成します。AccessKey ペアを作成して認証用の 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 倍のレートで課金されます。ビジネスニーズに基づいてスキームタイプを選択してください。 次のようにプロパティを設定します。
[DNSResolver share].scheme = DNSResolverSchemeHttps;
3. キャッシュの有効化または無効化
有効にすると、名前解決の結果がローカルにキャッシュされるため、以降の検索はキャッシュから即座に返されます。
キャッシュはデフォルトで有効になっています。無効にするには、次のコードを使用します:
[DNSResolver share].cacheEnable=NO;
4. ドメインのキープアライブキャッシュの設定
有効にすると、SDK は指定されたドメインのキャッシュエントリを有効期限が切れる前に事前に更新します。これによりデータが最新の状態に保たれますが、名前解決リクエストとネットワークトラフィックが増加します。この機能がない場合、キャッシュの更新は名前解決メソッドが呼び出されたときにのみ発生します。
// 配列には最大 10 個のドメインを含めることができます。
[[DNSResolver share] setKeepAliveDomains:@[@"www.taobao.com",@"www.aliyun.com"]];
-
メリット:
-
レコードが迅速に更新されます (TTL が期限切れになる前)。
-
事前解決と組み合わせると、初回解決時のレイテンシーを 0 ミリ秒に削減できます。
-
-
デメリット:レコードの 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 が最初に返されます。
IP 速度測定はデフォルトで無効になっています。有効にするには、次のコードを使用します:
[DNSResolver share].speedTestEnable=YES;
5. IP 速度測定方式の設定
プローブ方式を設定します。ICMP プローブの場合は 0 に設定し、特定のポート (80、443 など) でのソケットプローブの場合はポート番号に設定します。
デフォルト値は 443 です。
[DNSResolver share].speedPort = 80;
6. ISP 固有のドメイン名キャッシュの有効化または無効化
有効にすると、キャッシュエントリは ISP ネットワークごとに分離されます。無効にすると、すべてのネットワークが単一のキャッシュを共有します。
ISP 固有のドメイン名キャッシュはデフォルトで有効になっています。
[DNSResolver share].ispEnable = YES;
7. ネガティブキャッシュの最大 TTL の設定
失敗した検索の結果を保存するネガティブキャッシュの最大 TTL を設定します。
デフォルト値は 30 秒です。ネガティブキャッシュのカスタム最大 TTL を設定するには、次のコードを使用します:
[DNSResolver share].maxNegativeCache = 30;
8. 最大キャッシュ TTL の設定
サーバーが提供する TTL 値に関わらず、エントリの有効期間に上限を設定するために、最大キャッシュ TTL を設定します。
デフォルト値は 3600 秒です。カスタム最大キャッシュ TTL を設定するには、次のコードを使用します:
[DNSResolver share].maxCacheTTL= 3600;
9. 不変キャッシュの有効化
[DNSResolver share].immutableCacheEnable = NO;// 不変キャッシュはデフォルトで無効になっています。
SDK には 3 つのキャッシュ更新メカニズムがあります。
-
不変キャッシュ:この機能が有効になっている場合、キャッシュはアプリケーションの実行中は常に有効として扱われます。SDK は有効期限のチェックと更新をスキップするため、名前解決リクエストの数が最小限に抑えられます。
有効にするには、
[DNSResolver share].immutableCacheEnable = YESを呼び出します。 -
アクティブキャッシュ更新:この機能により、名前解決リクエストで常に最新のキャッシュが使用されるようになります。ドメインの権威レコードが変更されても、この仕組みによりキャッシュレコードは最新の状態に保たれるため、リクエストは低レイテンシーでキャッシュから応答を得られます。配列は最大 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を返し、その後、非同期でキャッシュを更新します。
-
10. タイムアウト
timeout プロパティは、解決のためのリクエスト タイムアウト を設定します。 デフォルト: 3 秒。 推奨範囲: 2 秒~ 5 秒。
サービス API
コード例:
/// 複数のドメインの情報を事前解決します。このメソッドはアプリ起動時に呼び出してください。結果をキャッシュに保存し、以降の名前解決を高速化します。
/// ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) を自動的に検出し、現在のネットワークに適した IP の配列を取得します。
/// @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 情報オブジェクトを 1 つ取得します。
/// キャッシングが有効な場合は、先にキャッシュからデータを返します。キャッシュが空または期限切れの場合は、ネットワーク経由で情報を取得します。キャッシングが無効な場合は、常にネットワーク経由で情報を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムなドメイン情報オブジェクトを 1 つ返すコールバック。
- (void)getRandomIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete;
/// ドメインのランダムな IPv6 情報オブジェクトを 1 つ取得します。
/// キャッシングが有効な場合は、先にキャッシュからデータを返します。キャッシュが空または期限切れの場合は、ネットワーク経由で情報を取得します。キャッシングが無効な場合は、常にネットワーク経由で情報を取得します。
/// @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 アドレスを 1 つ取得します。
/// キャッシングが有効な場合は、先にキャッシュからデータを返します。キャッシュが空または期限切れの場合は、ネットワーク経由で IP を取得します。キャッシングが無効な場合は、常にネットワーク経由で IP を取得します。
/// @param domain ドメイン名。
/// @param complete ランダムな IP アドレスを 1 つ返すコールバック。
- (void)getRandomIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete;
/// ドメインのランダムな IPv6 アドレスを 1 つ取得します。
/// キャッシングが有効な場合は、先にキャッシュからデータを返します。キャッシュが空または期限切れの場合は、ネットワーク経由で 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: URL 接続に IP アドレスを使用します。
}
}];
3. キャッシュから直接解決結果の取得
API 宣言:
/// 待機せずにキャッシュから直接 IP アドレスの配列を取得します。 このメソッドは、ネットワーク環境 (IPv4 のみ、IPv6 のみ、またはデュアルスタック) に自動的に適応します。
/// キャッシュが空の場合は nil を返します。 キャッシュが空でなく、`enable` が YES に設定されている場合、キャッシュデータを返します。 データが期限切れの場合、非同期にキャッシュを更新します。 キャッシュが空でなく、`enable` が NO に設定されている場合、期限切れのエントリの場合は nil を返し、非同期にキャッシュを更新します。
/// @param domain ドメイン名。
/// @param enable 期限切れの IP アドレスを返すかどうかを指定します。
- (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;
呼び出し例:
NSArray *result = [[DNSResolver share] getIpsByCacheWithDomain:@"your_domain" andExpiredIPEnabled:YES];
// キャッシュされた結果を使用します。
if (result.count > 0) {
//TODO: URL 接続に IP アドレスを使用します。
}
注: キャッシュから直接結果を取得するのは高速ですが、キャッシュが空の場合、またはキャッシュが期限切れで、かつ enable が NO に設定されている場合、メソッドは nil を返します。
4. キャッシュのクリア
API 宣言:
/// `hostArray` は、キャッシュからクリアするホスト名の配列です。 すべてのデータをクリアするには、nil または空の配列を渡してください。
-(void)clearHostCache:(NSArray <NSString *>*)hostArray;
呼び出し例:
[[DNSResolver share] clearHostCache:@[@"domain1", @"domain2"]];
5. 統計の収集
API 宣言:
/// リクエスト統計を収集します。
-(NSArray *)getRequestReportInfo;
呼び出し例:
NSArray *array = [[DNSResolver share] getRequestReportInfo];
データ形式:
(
{
avgRtt = "1"; // ドメイン解決の平均時間 (ミリ秒)
cacheDnsNum = 0; // キャッシュヒット数
domain = "www.taobao.com"; // 解決されたドメイン
gobackLocaldnsNum = 0; // ローカル DNS へのフォールバック数
localErro = 0; // ローカル DNS 解決の失敗数
maxRtt = "60"; // ドメイン解決の最大時間 (ミリ秒)
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 を組み合わせます。
アプリの起動時に重要なドメインを事前解決するとキャッシュが作成され、以降のルックアップでネットワークラウンドトリップを回避できるため、ほぼゼロレイテンシーでの名前解決を実現できます。
SDK に組み込まれたキャッシュは、事前解決済みドメインに対する以降の名前解決リクエストを直接処理します。これによりネットワークラウンドトリップを回避でき、ユーザー体験が大幅に向上します。
1. 事前解決
キャッシュを有効にし、アプリの起動時に重要なドメインを事前解決します。
AppDelegate の application:didFinishLaunchingWithOptions: メソッドで、アプリケーションで使用するドメイン名を事前解決し、結果をローカルメモリにキャッシュします。
1. IPv4 のみの場合
//******** IPv4 のみの場合 *******
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
DNSResolver *resolver = [DNSResolver share];
// setAccountId:@"******":アスタリスクを、コンソールの [アクセス構成] ページにある Account 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:@"******":アスタリスクを、コンソールの [アクセス構成] ページにある Account 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(@"Fast cache hit. Domain %@ resolved to 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(@"Async resolution complete. Domain %@ resolved to IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
NSLog(@"Domain resolution failed. Falling back to original domain.");
[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(@"Fast cache hit. Domain %@ resolved to 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(@"Async resolution complete. Domain %@ resolved to IP: %@", domain, ip);
[ws requestWithIP:ip domain:domain]; // IP を使用して直接接続します。
} else {
NSLog(@"Domain resolution failed. Falling back to original domain.");
[ws requestWithIP:domain domain:domain]; // フォールバック:元のドメインを使用します。
}
}];
}
使用上の注意
-
pdns-sdk-ios.frameworkには、iOS 9.0 以降が必要です。 -
HTTP 経由でリクエストを行う場合、
Info.plistファイルでApp Transport Security Settings->Allow Arbitrary LoadsをYESに設定する必要があります。 -
HTTPDNS から IP を解決した後、サービスリクエストを行う際に、
ホストHTTP ヘッダーを元のドメイン名に設定します。例:
// `ip` は元のドメイン名から解決された IP アドレスです。 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", ip]]; NSMutableURLRequest *mutableReq = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval: 10]; // ホストを設定します。 [mutableReq setValue:@"original_domain" forHTTPHeaderField:@"host"]; -
フォールバックメカニズムを実装してください。SDK が IP を返さない場合は、元のドメイン名を使用してリクエストを行ってください。
NSArray *array = [[DNSResolver share] getIpsByCacheWithDomain:@"original_domain" andExpiredIPEnabled:YES]; if (array && array.count > 0 && array.firstObject.length > 0) { // URL のホストを IP に置き換えてリクエストを行います。 } else { // フォールバックロジックを実装します (リクエストには元の URL を使用します)。 } -
中間 HTTP プロキシが存在する場合、クライアントリクエストはリクエストラインに絶対 URL を使用します。HTTPDNS を有効にして IP URL を使用すると、中間プロキシは URL から IP アドレスを識別し、それをホスト情報としてターゲットサーバーに渡します。その結果、ターゲットサーバーは実際のホスト情報がない HTTP リクエストを処理できません。デバイスでネットワークプロキシが有効になっているかどうかを確認することを推奨します。デバイスがプロキシモードの場合は、名前解決に HTTPDNS を使用しないでください。
オンプレミス 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 の高可用性ディザスタリカバリのための 3 つのコア API が含まれています。これらの API は、オンプレミス DNS サービスを構成し、セキュリティポリシーを制御し、プライマリ/バックアップの自動フェイルオーバーを実装します。
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 を 1 分ごとにプローブし、サービスの可用性を確認します。プローブが成功すると、サービス状態は alive に復元され、再びリクエストを処理できるようになります。
* @param accessKeyId 認証用のアクセスキー ID。
* @param 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;