全部产品
云市场

iOS SDK手册

更新时间:2019-09-11 16:50:24

1. 前言

本文档介绍了HTTPDNS iOS SDK的使用方式。

HTTPDNS是阿里云面向移动开发者提供的移动端DNS解析服务。通过该SDK,开发者可以在自己的iOS APP中获得可靠、实时、精准的DNS解析服务,彻底解决传统DNS面临的域名劫持、解析时延长、调度不精准等问题。

您可以通过获取 alicloud-ios-demo 工程源码获得HTTPDNS服务的使用例程。

1.1 手动集成SDK

  • 您可以通过上述 GitHub demo获取 HTTPDNS SDK
  • 您可以通过访问移动服务APP列表页(https://emas.console.aliyun.com/ 若您第一次访问,请创建 APP),勾选下图红框中的 HTTPDNS 组件获取 SDK。

ams

1.2 Pod集成

  • 指定Master仓库和阿里云仓库:
  1. source 'https://github.com/CocoaPods/Specs.git'
  2. source 'https://github.com/aliyun/aliyun-specs.git'
  • 添加依赖:
  1. pod 'AlicloudHTTPDNS', '~> 1.7.1'

(~>为模糊指定版本号方式,~> 1.7.1表明引用版本位于1.7.1 <= version < 1.8.0之间的最新版本SDK,用户可参考Podfile Syntax Reference,根据项目需要指定SDK版本。)

1.3 修改编译选项

Target->Linking->Other Linker Flags中添加 -ObjC-lz 选项。

不知道如何修改编译选项?请参考:

如何修改编译选项

注意:请注意 -ObjC 的大小写。


2. 应用程序配置与初始化

HTTPDNS iOS SDK,自v1.1.0版本已全面支持苹果ATS要求,无需在Info.plist中配置ATS。

2.1 依赖

系统公共库:

  • libsqlite3.0.tbd
  • libresolv.tbd
  • CoreTelephony.framework
  • SystemConfiguration.framework

AMS组件包

  • AlicloudHttpDNS.framework
  • UTDID.framework
  • AlicloudUtils.framework
  • UTMini.framework

如果遇到 UTDID 冲突可参考:《阿里云-移动云产品SDK UTDID冲突解决方案》

2.2 获取服务实例

HTTPDNS iOS SDK以全局service实例的方式提供域名解析服务,您可以通过以下方式获取实例:

  1. // 设置AccoutID,当您开通HTTPDNS服务时,您可以在控制台获取到您对应的Accout ID信息
  2. HttpDnsService *httpdns = [[HttpDnsService alloc] initWithAccountID::*****];

除了上面的方式,你还可以通过下面的方式进行初始化:

下载SDK统一配置文件

  • 在控制台产品概览页面,下载App的配置文件AliyunEmasServices-Info.plist,如下图所示:unit_config_pic

  • Xcode中,把下载的AliyunEmasServices-Info.plist文件拖入对应App Target下即可,在弹出框勾选Copy items if needed

  • 【附】AliyunEmasServices-Info.plist配置文件,包含SDK初始化所需的配置信息,用户只需要调用无需手动输入配置信息的autoInit初始化接口。

2.3 设置预解析域名

在您初始化程序时,可以选择性地预先向HTTPDNS SDK中注册您后续可能会使用到的域名,以便SDK提前解析,减少后续解析域名时请求的时延。您只需调用以下接口:

  1. NSArray * hosts = [[NSArray alloc] initWithObjects:@"www.taobao.com", @"www.aliyun.com", nil];
  2. [httpdns setPreResolveHosts:hosts];

注意预解析接口设置的同时会实时触发异步网络请求,应该在代码逻辑上确保调用预解析接口时,已经进行了必备的初始化设置。

比如:setHTTPSRequestEnabled: 需要在预解析接口之前调用,否则会导致预解析的相关 IP 采用 HTTP请求。

2.4 启用鉴权功能

首先需要在控制台开启鉴权功能:

open auth feature

在控制台开启鉴权功能后,SDK 需要更改初始化方式,改用下面的方法进行初始化,即可开启鉴权:

  1. /*!
  2. * @brief 启用鉴权功能的初始化接口
  3. * @details 初始化、开启鉴权功能,并设置 HTTPDNS 服务 Account ID,鉴权功能对应的 secretKey。
  4. * 您可以从控制台获取您的 Account ID 、secretKey 信息。
  5. * 此方法会初始化为单例。
  6. * @param accountId 您的 HTTPDNS Account ID
  7. * @param secretKey 鉴权对应的 secretKey
  8. */
  9. - (instancetype)initWithAccountID:(int)accountID secretKey:(NSString *)secretKey;

目前 iOS SDK 鉴权时间戳过期时间统一为 10 分钟,鉴权机制细节可以参考《HTTPDNS > 开发指南 > HTTP API手册 > 鉴权解析接口》

同时鉴权功能,支持对设备的时间进行校对,对应的方法为:

  1. /*!
  2. * @brief 校正 App 签名时间
  3. * @param authCurrentTime 用于校正的时间戳,正整数。
  4. * @details 不进行该操作,将以设备时间为准,为`(NSUInteger)[[NSDate date] timeIntervalSince1970]`。进行该操作后,如果有偏差,每次网络请求都会对设备时间进行矫正。
  5. * @attention 校正操作在 APP 的一个生命周期内生效,APP 重启后需要重新设置才能重新生效。可以重复设置。
  6. */
  7. - (void)setAuthCurrentTime:(NSUInteger)authCurrentTime;

3. 服务API与使用示例

3.1 服务API

  1. /**
  2. * 初始化并设置 HTTPDNS 服务 Account ID,您可以从控制台获取您的 Account ID 信息
  3. * 此方法会初始化为单例。
  4. * @param accountId 您的 HTTPDNS Account ID
  5. */
  6. - (instancetype)initWithAccountID:(int)accountID;
  7. /*!
  8. * @brief 启用鉴权功能的初始化接口
  9. * @details 初始化、开启鉴权功能,并设置 HTTPDNS 服务 Account ID,鉴权功能对应的 secretKey。
  10. * 您可以从控制台获取您的 Account ID 、secretKey 信息。
  11. * 此方法会初始化为单例。
  12. * @param accountId 您的 HTTPDNS Account ID
  13. * @param secretKey 鉴权对应的 secretKey
  14. */
  15. - (instancetype)initWithAccountID:(int)accountID secretKey:(NSString *)secretKey;
  16. /*!
  17. * @brief 校正 App 签名时间
  18. * @param authCurrentTime 用于校正的时间戳,正整数。
  19. * @details 不进行该操作,将以设备时间为准,为`(NSUInteger)[[NSDate date] timeIntervalSince1970]`。进行该操作后,如果有偏差,每次网络请求都会对设备时间进行矫正。
  20. * @attention 校正操作在 APP 的一个生命周期内生效,APP 重启后需要重新设置才能重新生效。可以重复设置。
  21. */
  22. - (void)setAuthCurrentTime:(NSUInteger)authCurrentTime;
  23. /**
  24. * 获取HTTPDNS服务实例
  25. */
  26. + (instancetype)sharedInstance;
  27. /**
  28. * 设置HTTPDNS域名解析请求类型(HTTP/HTTPS),若不调用该接口,默认为HTTP请求。
  29. * HTTP请求基于底层CFNetwork实现,不受ATS限制;
  30. *
  31. * @param enable YES: HTTPS请求, NO: HTTP请求
  32. */
  33. - (void)setHTTPSRequestEnabled:(BOOL)enable;
  34. /**
  35. * 设置持久化缓存功能
  36. * 开启后,每次网络解析记录,会更新到本地缓存,
  37. * App重启后,首先加载本地缓存到内存中,
  38. * 在网络解析返回前,优先使用缓存记录。利于优化App启动时数据加载性能。
  39. * 该功能旨在提升首屏加载速度,但持久化缓存会将上一次解析到的结果保存到本地持久层,app重启后,如果启动持久化缓存会优先从持久层加载解析结果。所以存在第一次使用的ip为过期ip(ttl过期,大多数情况下该ip依然可以正常使用)的可能性。如果业务服务器ip变化较频繁,建议谨慎接入该功能,以免对业务造成影响。另外,持久化缓存仅影响第一次域名解析结果,后续解析仍会请求httpdns服务器,并更新本地缓存。
  40. @param enable True:开启,False:关闭
  41. */
  42. - (void)setCachedIPEnabled:(BOOL)enable;
  43. /**
  44. * 将app使用到的域名预设进来,以便于HTTPDNS 进行预解析
  45. *
  46. * @param hosts 预解析列表
  47. */
  48. - (void)setPreResolveHosts:(NSArray *)hosts;
  49. /**
  50. * 异步解析接口,首先查询缓存,若存在则返回结果,若不存在返回nil并且进行异步域名解析更新缓存
  51. *
  52. * @param host 域名(如www.aliyun.com)
  53. * @return 域名对应的解析结果
  54. */
  55. - (NSString *)getIpByHostAsync:(NSString *)host;
  56. /**
  57. * 异步解析接口,首先查询缓存,若存在则返回结果列表,若不存在返回nil并且进行异步域名解析更新缓存
  58. *
  59. * @param host 域名(如www.aliyun.com)
  60. * @return 域名对应的解析结果列表
  61. */
  62. - (NSArray *)getIpsByHostAsync:(NSString *)host;
  63. /**
  64. * 异步解析接口,首先查询缓存,若存在则返回结果,若不存在返回空对象并且进行异步域名解析更新缓存。返回的结果是URL使用场景下的格式化结果
  65. *
  66. * @param host 域名(如www.aliyun.com)
  67. * @return 域名对应的解析结果
  68. */
  69. - (NSString *)getIpByHostAsyncInURLFormat:(NSString *)host;
  70. /**
  71. * 开启IPv6结果解析,开启后调用 getIPv6ByHostAsync: 接口使用
  72. *【注意】开启IPv6结果解析后,SDK在IPv6-Only网络环境下,对IPv4解析结果不再自动转换为IPv6地址,getIpsByHostAsync:返回IPv4地址,getIPv6ByHostAsync:返回IPv6地址
  73. *
  74. * @param enable 是否开启,默认为NO
  75. */
  76. - (void)enableIPv6:(BOOL)enable;
  77. /**
  78. * 异步解析域名,返回IPv6地址
  79. * 开启IPv6结果解析后,若域名存在IPv6地址,则返回IPv6解析结果
  80. *
  81. * 例:域名:ipv6.sjtu.edu.cn,IPv4地址:202.120.2.47,IPv6地址:2001:da8:8000:1:0:0:0:80,解析成功后接口返回结果:2001:da8:8000:1:0:0:0:80
  82. * @param host 解析域名
  83. * @return IPv6解析结果,若没有IPv6地址,则返回nil
  84. */
  85. - (NSString *)getIPv6ByHostAsync:(NSString *)host;
  86. /**
  87. * 设置降级策略,用户可定制规则降级为原生DNS解析方式;
  88. *
  89. * @param delegate 降级代理
  90. */
  91. - (void)setDelegateForDegradationFilter:(id<HttpDNSDegradationDelegate>)delegate;
  92. @protocol HttpDNSDegradationDelegate <NSObject>
  93. /**
  94. * 降级过滤器
  95. *
  96. * @param hostName 当前的目标域名(如www.aliyun.com),您可以针对域名进行降级过滤
  97. * @return 是否降级走原生DNS逻辑
  98. */
  99. - (BOOL)shouldDegradeHTTPDNS:(NSString *)hostName;
  100. @end
  101. /**
  102. * 是否允许HTTPDNS返回TTL过期的域名
  103. * 当您允许返回TTL过期的IP时,SDK在实时返回过期IP的同时依然会进行异步更新以获取最新的IP信息
  104. *
  105. * @param enable 是否返回TTL过期域名
  106. */
  107. - (void)setExpiredIPEnabled:(BOOL)enable;
  108. /**
  109. * 本地日志 log 开关
  110. */
  111. - (void)setLogEnabled:(BOOL)enable;
  112. /**
  113. * 设置网络切换时是否自动刷新所有域名解析结果,如果打开此开关,在网络切换时,会自动刷新所有域名的解析结果,但会产生一定流量消耗
  114. *
  115. * @param enable
  116. */
  117. - (void)setPreResolveAfterNetworkChanged:(BOOL)enable;
  118. /*!
  119. * 设置网络请求的超时时间
  120. * 超时时间默认为15秒
  121. * @param timeoutInterval 超时时间,单位为秒
  122. */
  123. - (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval;
  124. /**
  125. * 获取用于用户追踪的sessionId
  126. * sessionId为随机生成,长度为12位,App生命周期内保持不变
  127. *
  128. * 为了排查可能的解析问题,需要您将sessionId和解析出的IP一起记录在日志中
  129. * 请参考: 解析异常排查之 “会话追踪方案” https://help.aliyun.com/document_detail/100530.html
  130. */
  131. - (NSString *)getSessionId;
  132. /**
  133. * 设置日志输出回调(v1.6.20及以上版本支持)
  134. */
  135. - (void)setLogHandler:(id<HttpdnsLoggerProtocol>)logHandler;
从安全角度我们强烈建议用户使用异步解析接口。在DDOS攻击等特殊场景下,HTTPDNS有可能会触发流量黑洞,此时同步接口就有可能出现短暂的请求解析超时等待,而异步接口的网络请求都是后台操作的,业务层面不会感知到请求超时的动作,能够做到对异常情况的冗余。
  1. /**
  2. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回nil
  3. *
  4. * @param host 域名(如www.aliyun.com)
  5. * @return 域名对应的解析结果
  6. */
  7. - (NSString *)getIpByHost:(NSString *)host;
  8. /**
  9. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果列表,若解析失败返回nil
  10. *
  11. * @param host 域名(如www.aliyun.com)
  12. * @return 域名对应的解析结果列表
  13. */
  14. - (NSArray *)getIpsByHost:(NSString *)host;
  15. /**
  16. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回空对象。返回的结果是URL使用场景下的格式化结果
  17. *
  18. * @param host 域名(如www.aliyun.com)
  19. * @return 域名对应的解析结果
  20. */
  21. - (NSString *)getIpByHostInURLFormat:(NSString *)host;

HTTPDNS 场景下兼容 IPv6-only 网络环境需要注意的细节:

当您使用 IP 形式的 URL 进行网络请求时,IPv4 与 IPv6 的 IP 地址使用方式略有不同:

即在URL中使用IPv6地址时需要在IPv6地址基础上额外加上[]。为了方便开发者的使用,HTTPDNS提供了适配URL格式的IP获取接口 -[HttpDnsService getIpByHostAsyncInURLFormat:]。当您通过HTTPDNS进行IP获取,并使用该IP进行基于URL的网络访问时,您可以通过上述API直接获取符合URL使用场景,格式化后的IP信息,如1.1.1.1[2001:db8:c000:221::]。如果您仅仅为了获取精准的IP信息并另做它用,您可以继续使用老接口 -[HttpDnsService getIpByHostAsync:]

3.2 使用示例

您可以通过获取alicloud-ios-demo工程源码获得HTTPDNS服务的使用例程。

4. 注意事项

4.1 请记录从HTTPDNS获取的IP及sessionId

我们提供了用于解析问题排查的解决方案,需要您将从HTTPDNS获取的IP及sessionId记录到日志中, 详情可以参考 《解析异常排查之 “会话追踪方案”》

4.2 HTTP请求头HOST字段设置

标准的HTTP协议中服务端会将HTTP请求头HOST字段的值作为请求的域名信息进行解析。使用HTTPDNS后,您可能需要将HTTP请求URL中的HOST字段替换为HTTPDNS解析获得的IP,这时标准的网络库会将您的IP赋值给HTTP请求头的HOST字段,进而导致服务端的解析异常(服务端认可的是您的域名信息,而非IP信息)。为了解决这个问题,您可以主动设置HTTP请求HOST字段的值,如:

  1. NSString *originalUrl = @"http://www.aliyun.com/";
  2. NSURL* url = [NSURL URLWithString:originalUrl];
  3. NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
  4. // 同步接口获取IP
  5. NSString* ip = [httpdns getIpByHostAsync:url.host];
  6. if (ip) {
  7. // 通过HTTPDNS获取IP成功,进行URL替换和HOST头设置
  8. NSRange hostFirstRange = [originalUrl rangeOfString: url.host];
  9. if (NSNotFound != hostFirstRange.location) {
  10. NSString* newUrl = [originalUrl stringByReplacingCharactersInRange:hostFirstRange withString:ip];
  11. request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:newUrl]];
  12. // 设置请求HOST字段
  13. [request setValue:url.host forHTTPHeaderField:@"host"];
  14. }
  15. }

部分网络库支持COOKIE的自动存储管理,当您使用HTTPDNS进行IP URL请求时,部分网络库会将您URL中的IP信息作为COOKIE对应的域名信息进行存储管理(而非HTTP请求头HOST字段信息),进而造成COOKIE管理与使用上的困扰,因此您需要关闭COOKIE的自动管理功能(默认关闭)。

4.4 HTTPS/WebView/SNI场景

4.5 代理情况下的使用

当存在中间HTTP代理时,客户端发起的请求中请求行会使用绝对路径的URL,在您开启HTTPDNS并采用IP URL进行访问时,中间代理将识别您的IP信息并将其作为真实访问的HOST信息传递给目标服务器,这时目标服务器将无法处理这类无真实HOST信息的HTTP请求。移动网关提供了X-Online-Host的私有协议字段来解决这个问题,比如:

  1. 目标URLhttp://www.aliyun.com/product/oss/
  2. 通过HTTPDNS解析出来的www.aliyun.comIP1.1.1.1
  3. 代理:10.0.0.172:80
  4. 您的HTTP请求头:
  5. GET http://1.1.1.1/product/oss/ HTTP/1.1 # 通过代理发起的HTTP请求头,请求行是一个绝对路径
  6. Host: www.aliyun.com # 这个Header会被代理网关忽略,代理网关会使用请求行绝对路径中的host字段作为源站的host,即1.1.1.1
  7. X-Online-Host: www.aliyun.com # 这个Header就是移动网关为了传递真实Host添加的私有头部,源站需要配置识别该私有头部以获取真实的Host信息

同样您可以通过下述方法进行X-Online-Host请求头域的设置,并在服务端设置对该私有头域的解析。

  1. [request setValue:url.host forHTTPHeaderField:@"X-Online-Host"];

在绝大多数场景下,我们建议您在代理模式下关闭HTTPDNS功能。