生产环境调用Bing地图API随机出现连接超时异常求助
Bing地图API并发调用随机连接超时问题
背景
应用已部署到生产服务器,通过并发调用Bing地图API(地址:https://dev.virtualearth.net/REST/v1/Locations)批量获取位置数据,运行基本正常,但会随机出现连接超时异常,影响稳定性。
调用代码
private async Task<BingResponse> GetBingResponse(string argUri) { try { WebRequest request = HttpWebRequest.Create(new Uri(argUri)); var response = await request.GetResponseAsync(); if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK) { using (Stream resStream = (response.GetResponseStream())) { DataContractJsonSerializer jsonData = new DataContractJsonSerializer(typeof(BingResponse)); return jsonData.ReadObject(resStream) as BingResponse; } } else return null; } catch (Exception ex) { XLLogger.Write("Exception with BingResponse URL"); return null; } }
异常详情(含中文翻译)
原始异常信息
{ "ClassName": "System.Net.WebException", "Message": "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (dev.virtualearth.net:443)", "Data": null, "InnerException": { "StatusCode": null, "Message": "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (dev.virtualearth.net:443)", "Data": {}, "InnerException": { "ClassName": "System.Net.Sockets.SocketException", "Message": "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.", "Data": null, "InnerException": null, "HelpURL": null, "StackTraceString": " at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)\r\n at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)\r\n at System.Net.HttpWebRequest.<>c__DisplayClass216_0.<CreateHttpClient>b__1>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)", "RemoteStackTraceString": null, "RemoteStackIndex": 0, "ExceptionMethod": null, "HResult": -2147467259, "Source": "System.Net.Sockets", "WatsonBuckets": null, "NativeErrorCode": 10060 }, "HelpLink": null, "Source": "System.Net.Http", "HResult": -2147467259, "StackTrace": " at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)\r\n at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)\r\n at System.Net.HttpWebRequest.SendRequest(Boolean async)\r\n at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)" }, "HelpURL": null, "StackTraceString": " at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location ---\r\n", "RemoteStackTraceString": null, "RemoteStackIndex": 0, "ExceptionMethod": null, "HResult": -2147467259, "Source": "System.Net.Requests", "WatsonBuckets": null }
中文翻译
- 顶层异常:System.Net.WebException:连接尝试失败,因为连接方在一段时间后未正确响应,或已建立的连接因目标主机未响应而失败。(dev.virtualearth.net:443)
- 内层Socket异常:System.Net.Sockets.SocketException(错误码10060):连接尝试失败,因为连接方在一段时间后未正确响应,或已建立的连接因目标主机未响应而失败。
解决方案
- 添加超时控制:给
HttpWebRequest设置合理的超时时间,避免无限制等待。比如在创建请求后加:((HttpWebRequest)request).Timeout = 10000; // 10秒超时 ((HttpWebRequest)request).ReadWriteTimeout = 15000; // 读写超时15秒 - 实现重试策略:针对连接超时这类临时异常,用指数退避法重试,最多3次,间隔依次为1秒、2秒、4秒,避免单次失败直接返回。
- 替换为HttpClient:
HttpWebRequest是旧API,HttpClient自带连接池,更适合并发场景,能减少连接资源浪费。示例:private static readonly HttpClient _httpClient = new HttpClient(); private async Task<BingResponse> GetBingResponse(string argUri) { try { var response = await _httpClient.GetAsync(argUri); if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); // 用JsonSerializer反序列化,替换DataContractJsonSerializer return JsonSerializer.Deserialize<BingResponse>(json); } return null; } catch (Exception ex) { XLLogger.Write($"Exception with BingResponse URL: {ex.Message}"); return null; } } - 限制并发量:Bing API有调用配额,并发太高可能被限流或导致自身连接池耗尽。用
SemaphoreSlim控制并发数,比如限制同时发送10个请求:private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(10); // 在调用GetBingResponse前: await _semaphore.WaitAsync(); try { var result = await GetBingResponse(uri); // 处理结果 } finally { _semaphore.Release(); } - 排查网络问题:确认生产服务器到dev.virtualearth.net的网络是否稳定,有无防火墙、代理拦截,可通过ping、telnet测试连通性。
内容的提问来源于stack exchange,提问作者Vignesh Kumar A
相关产品推荐
相关产品推荐

