全部产品

iOS SDK 开发手册

更新时间:2020-09-11 16:33:53

1. 前言

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

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

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


1.1 手动集成 SDK

  • 您可以通过访问移动服务 APP 列表页 ( 若您第一次访问,请创建 APP ),勾选下图红框中的 HTTPDNS 组件获取 SDK。

    AMSAMS1


1.2 Pos 集成

  • 指定 Master 仓库和阿里云仓库:
    1. source 'https://github.com/CocoaPods/Specs.git'
    2. source 'https://github.com/aliyun/aliyun-specs.git'
  • 添加依赖:
    1. pod 'AlicloudHTTPDNS', '~> 1.19.2.4'
    (~>为模糊指定版本号方式,~> 1.19.2.4表明引用版本位于1.19.2.4 <= version < 1.20.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

HTTPDNS 组件包

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

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


2.2 获取服务实例

一、建议使用 SDK 自动初始化接口, 结合 AliyunEmasServices-Info.plist 配置文件使用 。AliyunEmasServices-Info.plist 配置文件,包含 SDK 初始化所需的配置信息,用户只需要调用 autoInit 初始化接口即可完成 SDK 初始化 ,无需手动输入配置信息
  1. - (instancetype)autoInit ;
  2. 示例:
  3. HttpDnsService *httpdns = [[HttpDnsService alloc] autoInit];
二、或者也可以通过以下方式获取实例 :
  1. // 设置 HTTPDNS AccoutID ,当您开通 HTTPDNS 服务时,您可以在控制台获取到您对应的 Accout ID 信息
  2. HttpDnsService *httpdns = [[HttpDnsService alloc] initWithAccountID::*****];

accountidimage


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

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


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. * 启用鉴权功能的初始化接口
  3. * 初始化 开启鉴权功能 并设置 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 分钟,鉴权机制细节可以参考 鉴权解析接口
同时鉴权功能,支持对设备的时间进行校对,对应的方法为:
  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

首先在AliyunEmasServices-Info.plist 获取您的 accountID 和 secretKey 。

HTTPDNSAPPKEYIMAGE

3.1.1 SDK 初始化 接口 :

  1. /**
  2. * SDK 自动初始化接口
  3. * 无需配置 appKey 和 appSecret;
  4. * 结合 AliyunEmasServices-Info.plist 配置文件使用。
  5. */
  6. - (instancetype)autoInit;
  7. /**
  8. * SDK 初始化接口
  9. * 初始化并设置 HTTPDNS 服务 Account ID,您可以从控制台获取您的 Account ID 信息
  10. * 此方法会初始化为单例。
  11. * @param accountId 您的 HTTPDNS Account ID
  12. */
  13. - (instancetype)initWithAccountID:(int)accountID;
  14. /**
  15. * SDK 启用鉴权功能的初始化接口
  16. * 初始化、开启鉴权功能,并设置 HTTPDNS 服务 Account ID,鉴权功能对应的 secretKey。
  17. * 您可以从控制台获取您的 Account ID 、secretKey 信息。
  18. * 此方法会初始化为单例。
  19. * @param accountId 您的 HTTPDNS Account ID
  20. * @param secretKey 鉴权对应的 secretKey
  21. */
  22. - (instancetype)initWithAccountID:(int)accountID secretKey:(NSString *)secretKey;
  23. /**
  24. * @brief 校正 App 签名时间
  25. * @param authCurrentTime 用于校正的时间戳,正整数。
  26. * @details 不进行该操作,将以设备时间为准,为`(NSUInteger)[[NSDate date] timeIntervalSince1970]`。
  27. * 进行该操作后,如果有偏差,每次网络请求都会对设备时间进行矫正。
  28. * @attention 校正操作在 APP 的一个生命周期内生效,APP 重启后需要重新设置才能重新生效。可以重复设置。
  29. */
  30. - (void)setAuthCurrentTime:(NSUInteger)authCurrentTime;

3.1.2 SDK HTTPDNS 服务实例化接口 :

  1. /**
  2. * HTTPDNS 服务实例化接口
  3. */
  4. + (instancetype)sharedInstance;

3.1.2.1 SDK HTTPDNS 本地日志接口 :

  1. /**
  2. * 本地日志 log 开关,上线时建议关闭。
  3. */
  4. - (void)setLogEnabled:(BOOL)enable;
  5. /**
  6. * 设置日志输出回调(v1.6.20及以上版本支持)
  7. */
  8. - (void)setLogHandler:(id<HttpdnsLoggerProtocol>)logHandler;

3.1.3 SDK HTTPDNS 偏好设置接口:

  1. /** 3.1.3.1
  2. * 设置 HTTPDNS 域名解析请求类型 ( HTTP / HTTPS )
  3. * 若不调用该接口,默认为 HTTP 请求。
  4. * HTTP 请求基于底层 CFNetwork 实现,不受 ATS 限制;
  5. * @param enable
  6. * YES: HTTPS请求
  7. * NO: HTTP请求
  8. */
  9. - (void)setHTTPSRequestEnabled:(BOOL)enable;
  10. /** 3.1.3.2
  11. * 设置持久化缓存功能
  12. * 开启后, 每次网络解析记录,会更新到本地缓存,
  13. * App 重启后,首先加载本地缓存到内存中,
  14. * 在网络解析返回前, 优先使用缓存记录。利于优化 App 启动时数据加载性能。
  15. * 该功能旨在提升首屏加载速度,但持久化缓存会将上一次解析到的结果保存到本地持久层,
  16. *App 重启后,如果启动持久化缓存会优先从持久层加载解析结果。
  17. * 所以存在第一次使用的 ip 为过期 ip(ttl过期,大多数情况下该 ip 依然可以正常使用)的可能性。
  18. * 如果业务服务器ip变化较频繁,建议谨慎接入该功能,以免对业务造成影响。
  19. * 另外,持久化缓存仅影响第一次域名解析结果,后续解析仍会请求httpdns服务器,并更新本地缓存。
  20. @param enable True:开启,False:关闭
  21. */
  22. - (void)setCachedIPEnabled:(BOOL)enable;
  23. /** 3.1.3.3
  24. * 预解析接口
  25. * 选择性的预先向 HTTPDNS SDK 中注册您后续可能会使用到的域名,
  26. * 以便 SDK 提前解析,减少后续解析域名时请求的时延
  27. * @param hosts 预解析列表
  28. */
  29. - (void)setPreResolveHosts:(NSArray *)hosts;
  30. /** 3.1.3.4
  31. * 是否允许 HTTPDNS 返回 TTL 过期域名的 ip ,建议允许(默认不允许)
  32. * 当您允许返回 TTL 过期的 IP 时,SDK在实时返回过期 IP 的同时 依然会进行异步更新以获取最新的 IP 信息
  33. * 当您不允许返回 TTL 过期的IP时,举例说明:
  34. * 1、已有某个域名的缓存,IP 的 TTL 时间为 60s,60s 内调用 getIpByHostAsync 等异步解析接口可以拿到缓存结果;
  35. * 2、但是在 60s 之后,由于 IP 已过期,首次调用 getIpByHostAsync 等异步解析接口会直接返回 null ,之后进行异步域名解析更新缓存。
  36. * @param enable 是否返回 TTL 过期域名
  37. */
  38. - (void)setExpiredIPEnabled:(BOOL)enable;
  39. /** 3.1.3.5
  40. * 设置网络切换时是否自动跟新所有域名解析结果,
  41. * 如果打开此开关,在网络切换时,会自动刷新所有域名的解析结果,但会产生一定流量消耗
  42. * @param enable
  43. */
  44. - (void)setPreResolveAfterNetworkChanged:(BOOL)enable;
  45. /** 3.1.3.6
  46. * 设置网络请求的超时时间
  47. * 超时时间默认为15秒
  48. * @param timeoutInterval 超时时间,单位为秒
  49. */
  50. - (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval;
  51. /** 3.1.3.7
  52. * 设置 region 节点,调用后,会按照 region 更新服务IP(v1.18 + 提供)
  53. * 注意:调用时,与上次设置region一样或者五分钟内重复设置不同region时,不会进行服务IP的更新
  54. * @param region region为节点,可设置海外region
  55. */
  56. - (void)setRegion:(NSString *)region;

3.1.4 SDK HTTPDNS 异步解析接口

  1. /** 3.1.4.1
  2. * 异步解析接口
  3. * 首先查询缓存,若存在则返回结果,若不存在返回 nil 并且进行异步域名解析更新缓存
  4. * @param host 域名 ( 如 www.aliyun.com )
  5. * @return 域名对应的解析结果
  6. */
  7. - (NSString *)getIpByHostAsync:(NSString *)host;
  8. /** 3.1.4.2
  9. * 异步解析接口
  10. * 首先查询缓存, 若存在则返回结果列表,若不存在返回 nil 并且进行异步域名解析更新缓存
  11. * @param host 域名 ( 如 www.aliyun.com )
  12. * @return 域名对应的解析结果列表
  13. */
  14. - (NSArray *)getIpsByHostAsync:(NSString *)host;
  15. /** 3.1.4.3
  16. * 异步解析接口
  17. * 首先查询缓存,若存在则返回结果,若不存在返回 空对象 并且进行异步域名解析更新缓存。
  18. * 返回的结果 是 URL 使用场景下的格式化结果
  19. * @param host 域名(如www.aliyun.com)
  20. * @return 域名对应的解析结果
  21. */
  22. - (NSString *)getIpByHostAsyncInURLFormat:(NSString *)host;

3.1.5 SDK HTTPDNS IPv6 异步解析接口

  1. /** 3.1.5.1
  2. * 设置是否 开启 IPv6 结果解析
  3. * 开启后调用 getIPv6ByHostAsync: 接口使用
  4. *【注意】开启 IPv6 结果解析后,SDK在 IPv6-Only 网络环境下,对 IPv4 解析结果不再自动转换为 IPv6 地址, getIpsByHostAsync:返回 IPv4 地址,getIPv6ByHostAsync:返回 IPv6 地址
  5. * @param enable 是否开启,默认为 NO
  6. */
  7. - (void)enableIPv6:(BOOL)enable;
  8. /** 3.1.5.2
  9. * IPv6 异步解析域名 返回 IPv6 地址
  10. * 开启 IPv6 结果解析后,若域名存在 IPv6 地址,则返回 IPv6 解析结果
  11. * 例:域名:ipv6.sjtu.edu.cn,IPv4 地址:202.120.2.47,IPv6地址:2001:da8:8000:1:0:0:0:80,
  12. * 解析成功后接口返回结果:2001:da8:8000:1:0:0:0:80
  13. * @param host 解析域名
  14. * @return IPv6解析结果,若没有IPv6地址,则返回nil
  15. */
  16. - (NSString *)getIPv6ByHostAsync:(NSString *)host;
  17. -------------------------------------------------------------------------------------
  18. 备注: HTTPDNS 场景下兼容 IPv6-only 网络环境需要注意的细节:
  19. 当您使用 IP 形式的 URL 进行网络请求时,IPv4 IPv6 IP 地址使用方式略有不同:
  20. - IPv4: http://1.1.1.1/path
  21. - IPv6: http://[2001:db8:c000:221::]/path
  22. 即在 URL 中使用 IPv6 地址时,需要在 IPv6 地址基础上额外加上 `[]`
  23. 为了方便开发者的使用,HTTPDNS 提供了适配 URL 格式的 IP 获取接口
  24. `-[HttpDnsService getIpByHostAsyncInURLFormat:]`
  25. 当您通过 HTTPDNS 进行 IP 获取,并使用该IP进行基于 URL 的网络访问时,
  26. 您可以通过上述 API 直接获取符合 URL 使用场景,格式化后的 IP 信息,
  27. *1.1.1.1*,*[2001:db8:c000:221::]*。
  28. 如果您仅仅为了获取精准的IP信息并另做它用:
  29. 您可以继续使用老接口 `-[HttpDnsService getIpByHostAsync:]`

3.1.6 SDK HTTPDNS 降级策略

  1. /**
  2. * 设置降级策略,用户可定制规则降级为原生 DNS 解析方式;
  3. * @param delegate 降级代理
  4. */
  5. - (void)setDelegateForDegradationFilter:(id<HttpDNSDegradationDelegate>)delegate;
  6. @protocol HttpDNSDegradationDelegate <NSObject>
  7. /**
  8. * 降级过滤器
  9. * @param hostName 当前的目标域名(如www.aliyun.com),您可以针对域名进行降级过滤
  10. * @return 是否降级走原生DNS逻辑
  11. */
  12. - (BOOL)shouldDegradeHTTPDNS:(NSString *)hostName;
  13. // 示例代码 :
  14. - (BOOL)shouldDegradeHTTPDNS:(NSString *)hostName {
  15. // 假设您禁止 "www.aliyun.com" 域名通过 HTTPDNS 进行解析
  16. if ([hostName isEqualToString:@"www.aliyun.com"]) {
  17. NSLog(@"The host is in blacklist. Degrade!");
  18. return YES;
  19. }
  20. return NO;
  21. }
  22. // 此时调用解析接口获取的的 ip 为 null
  23. NSString *ip = [httpdns getIpByHostAsync:@"www.aliyun.com"];

3.1.7 SDK HTTPDNS 排查追踪

  1. /**
  2. * 获取用于用户追踪的 sessionId
  3. * sessionId为随机生成,长度为 12 位,App 生命周期内保持不变
  4. * 为了排查可能的解析问题,需要您将 sessionId 和解析出的 IP 一起记录在日志中
  5. * 请参考: 解析异常排查之 “会话追踪方案” https://help.aliyun.com/document_detail/100530.html
  6. */
  7. - (NSString *)getSessionId;

3.1.8 SDK HTTPDNS 同步解析接口 (新版本 SDK 同步接口 已废弃)

从安全角度我们强烈建议用户使用异步解析接口。在DDOS攻击等特殊场景下,HTTPDNS有可能会触发流量黑洞,此时同步接口就有可能出现短暂的请求解析超时等待,而异步接口的网络请求都是后台操作的,业务层面不会感知到请求超时的动作,能够做到对异常情况的冗余。
  1. /**
  2. * 同步解析接口,
  3. * 首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回 nil
  4. * @param host 域名(如www.aliyun.com)
  5. * @return 域名对应的解析结果
  6. */
  7. - (NSString *)getIpByHost:(NSString *)host;
  8. /**
  9. * 同步解析接口,
  10. * 首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果列表,若解析失败返回 nil
  11. * @param host 域名(如www.aliyun.com)
  12. * @return 域名对应的解析结果列表
  13. */
  14. - (NSArray *)getIpsByHost:(NSString *)host;
  15. /**
  16. * 同步解析接口,
  17. * 首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回空对象。
  18. * 返回的结果是URL使用场景下的格式化结果
  19. * @param host 域名(如www.aliyun.com)
  20. * @return 域名对应的解析结果
  21. */
  22. - (NSString *)getIpByHostInURLFormat:(NSString *)host;

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 功能。