iOS Ping 域名,多个动态域名选择
因为我们的请求域名会出现一些情况导致无法使用的情况,所以在 App 发起数据请求之前,就要确定一个可使用的域名。这就是这次需求的目的。
动态域名选择条件
1、默认 IP 地址(防止基础域名和其他可选域名全都没用)。
2、基础域名(就是你默认的那个域名)。
废话不多说,看代码
- (void)pingHostURL:(NSString *)hostURL
{
NSURL *candidate = [NSURL URLWithString:hostURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidate];
[request setHTTPMethod:@"HEAD"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
BOOL isSuccess = YES;
if (error) {
NSLog(@"pingHostURL:%@ 不可用", hostURL);
isSuccess = NO;
}else{
isSuccess = YES;
NSLog(@"pingHostURL:%@ 可用", hostURL);
}
[self.hostBoolDict setValue:[NSNumber numberWithBool:isSuccess] forKey:hostURL];
[self pingSuccess:isSuccess host:hostURL];
}];
[task resume];
}
假如你有多个域名要去循环 ping 来进行选择,一个 for 循环,一个 NSMutableDictionary,一个 ping 的结果的处理方法。
- (void)pingSuccess:(BOOL)success host:(NSString *)hostURL
{
NSLog(@"ping 的 hostURL = %@, 成功与否 = %i", hostURL, success);
if (!success) { // 当前域名无法 ping 通
NSLog(@"ping 失败的 hostURL = %@", hostURL);
NSArray *valueArr = [self.hostBoolDict allValues];
NSLog(@"VALUEARR = %@ , self.hostURLs = %@", valueArr, self.hostURLs);
for (NSNumber *number in valueArr) {
if ([number boolValue]) { // 存在成功过的域名
return;
}
}
// 全部备用域名 ping 失败之后,才选择 IP 地址
if (valueArr.count < self.hostURLs.count) {
return;
}
if (self.pingingType == DDHostPingPingingTypeClientInit) {
self.startClientInitPing = NO;
self.hasPingClientInitHost = YES;
} else if (self.pingingType == DDHostPingPingingTypeOther) {
self.startOtherPing = NO;
}
// 测试环境
if ([HostUrlManager shareInstance].Env == TestType) {
NSString *ipHostURL = @"http://xx.xxx.xxx.xx"; // IP 地址
self.currentHostUrl = ipHostURL;
[[HostUrlManager shareInstance] configIPHostURL:ipHostURL];
} else if ([HostUrlManager shareInstance].Env == ReleaseType) { // 正式环境
NSString *ipHostURL = @"http://xx.xxx.xxx.xx"; // IP 地址
self.currentHostUrl = ipHostURL;
[[HostUrlManager shareInstance] configIPHostURL:ipHostURL];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(hostPingManagerCompletionWithHost:success:)]) {
[self.delegate hostPingManagerCompletionWithHost:self.currentHostUrl success:success];
}
} else {
if (self.pingingType == DDHostPingPingingTypeClientInit) {
self.startClientInitPing = NO;
self.hasPingClientInitHost = YES;
} else if (self.pingingType == DDHostPingPingingTypeOther) {
self.startOtherPing = NO;
}
BOOL isDebug = NO;
if ([HostUrlManager shareInstance].Env == TestType) {
isDebug = YES;
} else if ([HostUrlManager shareInstance].Env == ReleaseType) {
isDebug = NO;
}
NSLog(@"ping 成功的 hostURL = %@", hostURL);
// 修改你的默认域名配置
self.currentHostUrl = hostURL;
[[HostUrlManager shareInstance] configDefaultHostURL:hostURL];
if (self.delegate && [self.delegate respondsToSelector:@selector(hostPingManagerCompletionWithHost:success:)]) {
[self.delegate hostPingManagerCompletionWithHost:self.currentHostUrl success:success];
}
}
}
代码解释
HostUrlManager 是一个网址单例,每次发起的请求的域名都是从它这边拿到的。所以有两个方法,第一个 configIPHostURL
第二个 configDefaultHostURL
内部会判断是否有 IP 地址,还有 default 地址,如果这两个存在,会优先 return defaultURL,目的就是尽量少使用 IP 地址。
自己遇到的难点
1、测试环境和正式环境的不同转换。
2、初始配置请求和其他网络请求的影响。
3、如果后端返回的域名能够 ping 通,但实际上他的域名不能使用,例如返回 https://www.baidu.com ,我们是能够 ping 通并替换掉默认的选项的。需要自己建立一个 reset 机制,如果使用这个域名,一分钟内请求多次不成功,就重新刷新为最初始的各个域名参数。
4、ping 在客户端的实际表达。用过 SimplePing, 也用过 Reachability 库来进行 ping 的表达。都不甚如人意。
工作较忙,文章较混乱,实在抱歉。如有建议,欢迎斧正。