如何在Xamarin iOS中处理超时异常
从你提供的错误日志来看,这是典型的**NSURLErrorDomain Code=-1001(请求超时)**错误,对应系统定义的NSURLErrorTimedOut,通常是因为网络请求在指定时间内没有得到服务器响应。下面是几种实用的处理方案:
1. 主动为请求设置合理的超时时间
不管你使用HttpClient还是原生NSUrlSession,都可以手动配置超时阈值,避免系统默认逻辑导致的意外报错:
针对HttpClient的配置
var httpClient = new HttpClient(); // 设置全局超时为15秒(可根据业务调整) httpClient.Timeout = TimeSpan.FromSeconds(15); try { var response = await httpClient.GetAsync("你的请求URL"); response.EnsureSuccessStatusCode(); // 处理正常响应逻辑 } catch (TaskCanceledException ex) { // HttpClient超时会抛出TaskCanceledException,需区分手动取消和超时 if (!ex.CancellationToken.IsCancellationRequested) { Console.WriteLine("请求超时:" + ex.Message); // 这里添加超时后的处理逻辑 } }
针对NSUrlSession的配置
var configuration = NSUrlSessionConfiguration.DefaultSessionConfiguration; // 单次请求的超时时间(比如15秒) configuration.TimeoutIntervalForRequest = 15; // 整个请求生命周期的超时时间(比如60秒) configuration.TimeoutIntervalForResource = 60; var session = NSUrlSession.FromConfiguration(configuration); var task = session.CreateDataTask(new NSUrlRequest(new NSUrl("你的请求URL")), (data, response, error) => { if (error != null && error.Code == -1001) { // 捕获到超时错误,处理逻辑 Console.WriteLine("请求超时:" + error.LocalizedDescription); } }); task.Resume();
2. 精准捕获不同场景下的超时异常
Xamarin iOS中网络超时可能抛出不同类型的异常,需要针对性判断:
try { // 执行你的网络请求操作 } catch (WebException ex) { if (ex.Status == WebExceptionStatus.Timeout) { // 处理HttpWebRequest的超时 ShowUserAlert("请求超时,请检查网络后重试"); } } catch (HttpRequestException ex) { // 针对HttpClient的超时,结合内部异常判断 if (ex.InnerException is TaskCanceledException tce && !tce.CancellationToken.IsCancellationRequested) { ShowUserAlert("请求超时,请稍后再试"); } } catch (NSErrorException ex) { // 捕获原生NSUrlSession抛出的超时错误 if (ex.Error.Code == -1001) { ShowUserAlert("请求超时,请检查网络连接"); } }
3. 添加超时自动重试机制
针对偶尔的网络波动导致的超时,可以用重试逻辑提升用户体验,比如借助Polly库(Xamarin完全支持)简化实现:
// 先安装Polly NuGet包 var retryPolicy = Policy .Handle<TaskCanceledException>(ex => !ex.CancellationToken.IsCancellationRequested) .Or<WebException>(ex => ex.Status == WebExceptionStatus.Timeout) .Or<NSErrorException>(ex => ex.Error.Code == -1001) .WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // 指数退避重试 // 用策略包裹请求逻辑 await retryPolicy.ExecuteAsync(async () => { var response = await httpClient.GetAsync("你的请求URL"); response.EnsureSuccessStatusCode(); // 处理响应 });
4. 给用户友好的错误反馈
捕获到超时异常后,不要只在日志里记录,还要给用户清晰的提示:
void ShowUserAlert(string message) { var alert = UIAlertController.Create("提示", message, UIAlertControllerStyle.Alert); alert.AddAction(UIAlertAction.Create("确定", UIAlertActionStyle.Default, null)); UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null); }
你的错误日志参考
2021-01-19 18:34:32.877465+0530 REPORT[7165:380896] [connection] nw_socket_handle_socket_event [C2.1:2] 套接字SO_ERROR [60: Operation timed out]
2021-01-19 18:34:32.886744+0530 REPORT[7165:380896] Connection 2: 收到失败通知
2021-01-19 18:34:32.889254+0530 REPORT[7165:380896] Connection 2: 连接失败 1:60, reason -1
2021-01-19 18:34:32.890389+0530 REPORT[7165:380896] Connection 2: encountered error(1:60)
2021-01-19 18:34:32.892589+0530 REPORT[7165:381682] Task .<1> HTTP加载失败, 0/0字节 (错误代码: -1001 [1:60])
2021-01-19 18:34:32.895246+0530 REPORT[7165:380952] Task .<1> 执行完成并出现错误 [-1001] Error Domain=NSURLErrorDomain Code=-1001 "请求超时。" UserInfo={_kCFStreamErrorCodeKey=60, NSUnderlyingError=0x600002b5eca0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=60, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask .<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask .<1>" ), NSLocalizedDescription=请求超时。, NSErrorFailingURLStringKey}
内容的提问来源于stack exchange,提问作者Nitish Kumar Tiwary

