iOS中如何检测服务器及页面可用性?WKWebView与Reachability问题
嘿,我看你遇到的问题挺典型的——用WKWebView时,碰到域名不存在或者服务器宕机的情况,didStartProvisionalNavigation触发后就没下文了,而且Reachability还误报说网络可达对吧?先给你揪出当前代码里的一个小错误,再给你两个靠谱的解决办法:
首先,你用Reachability的时候犯了个小错:reachabilityWithHostname:需要传的是纯主机名(比如chess.math.science.google.com),但你传的是完整的URL(带https://那种),这就导致Reachability的判断完全不准,日志里显示ReachableViaWiFi其实是无效的。赶紧改成这样:
Reachability* tinyReach = [Reachability reachabilityWithHostname:webView.URL.host];
接下来解决核心问题——WKWebView在域名挂了的时候没反应,我们可以从两个方向入手:
1. 用WKWebView的代理捕获导航失败
WKWebView其实有专门的代理方法处理导航启动阶段的错误,就是didFailProvisionalNavigation:,域名解析失败、服务器连不上、请求超时这些情况都会触发这个方法,你把它实现了就能像Chrome那样给用户提示了:
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { NSLog(@"加载出错啦: %@", error.localizedDescription); // 根据错误码给用户不同的提示 switch (error.code) { case NSURLErrorCannotFindHost: // 找不到域名对应的IP,和Chrome的提示一致 [self showErrorAlert:@"无法访问此网站,服务器IP地址无法找到"]; break; case NSURLErrorCannotConnectToHost: // 服务器宕机或者拒绝连接 [self showErrorAlert:@"无法连接到服务器,请稍后再试"]; break; case NSURLErrorTimedOut: // 请求超时了 [self showErrorAlert:@"请求超时,请检查你的网络连接"]; break; default: [self showErrorAlert:@"加载失败: %@", error.localizedDescription]; break; } } // 写个辅助方法弹提示框 - (void)showErrorAlert:(NSString *)message { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; }
2. 提前发个轻量请求验证URL可用性
要是你想在WKWebView开始加载前就确认这个URL能不能用,可以提前发个HEAD请求(比GET请求轻,只拿响应头),这样能提前知道服务器状态,避免WKWebView卡住没反应:
- (void)checkURLBeforeLoad:(NSURL *)targetURL { NSURLRequest *checkRequest = [NSURLRequest requestWithURL:targetURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0]; NSURLSessionDataTask *checkTask = [[NSURLSession sharedSession] dataTaskWithRequest:checkRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 切回主线程更新UI dispatch_async(dispatch_get_main_queue(), ^{ if (error) { // 请求失败,直接弹提示 [self showErrorAlert:error.localizedDescription]; } else { // 没问题,再让WKWebView加载 [self.webView loadRequest:checkRequest]; } }); }]; [checkTask resume]; }
用的时候就直接调用这个方法,而不是直接让WKWebView加载:
NSURL *urlToLoad = [NSURL URLWithString:@"https://chess.math.science.google.com"]; [self checkURLBeforeLoad:urlToLoad];
最后再啰嗦两句
Reachability只能帮你判断设备有没有连上网、能不能和某个主机建立TCP连接,但它管不了这个主机能不能正常返回HTTP内容,所以不能靠它来验证页面可用性。把上面的代理方法和提前请求的方式结合起来,就能覆盖大部分场景了——不管是域名解析失败、服务器宕机,还是404/500这些HTTP错误,都能处理到位。
内容的提问来源于stack exchange,提问作者propstm

