在后台尝试使用
HttpClient
从 React/.NET 应用程序调用外部 API 时,有时我们会看到如下 http 异常:
System.Net.Http.HttpRequestException:连接尝试失败,因为连接方在一段时间后没有正确响应,或者由于连接的主机未能响应而建立的连接失败。 (--url--)
System.Net.Sockets.SocketException (10060):连接尝试失败,因为连接方在一段时间后没有正确响应,或者由于连接的主机未能响应而建立的连接失败。
System.Net.Http.HttpRequestException:无法建立连接,因为目标机器主动拒绝。 (--url--)
System.Net.Sockets.SocketException (10061):无法建立连接,因为目标机器主动拒绝。
这是创建
HttpClient
的代码:
services.AddHttpClient("SearchClient", client =>
{
client.BaseAddress = new Uri(settings.SearchUrl);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.Timeout = TimeSpan.FromSeconds(settings.APITimeoutInSeconds);
});
services.AddHttpClient("LoginClient", client =>
{
client.BaseAddress = new Uri(settings.LoginUrl);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.Timeout = TimeSpan.FromSeconds(settings.APITimeoutInSeconds);
});
将在单例作用域实例类中使用以下代码实例化这些实例,
var client = _httpClientFactory.CreateClient("LoginClient");
using (var response = await client.PostAsync(requestUri, content))
{
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
res = JsonConvert.DeserializeObject<TokenResponseModel>(responseContent);
}
else
{
apiLog.Response = response;
}
}
知道如何解决这些问题吗?
HTTP/HTTPS 是基于 TCP/IP 网络协议构建的网络协议。 TCP/IP 协议使用 SYN、ACK、SYN/ACK 范例。该范式进一步转化为数据包传输会话将遵循以下步骤的事实:发送方将数据包发送给接收方,接收方接收数据包并检查数据包的TCP标头中的校验和,然后接收方做出响应向发送方告知数据包已成功接收,或者数据包已收到但数据损坏,或者如果未收到数据包,接收方根本不响应发送方。这种范例是为TCP/IP协议制定的,因为它的目的是确保使用该协议传输的数据的完整性。这意味着您遇到的行为是正常的,因为在数据传输过程中可能会干扰许多变量。
// INCREASE THE DURATION OF THE DATA TRANSMISSION SESSION
var client = _httpClientFactory.CreateClient("LoginClient");
client.Timeout = TimeSpan.FromSeconds(5);
using (var response = await client.PostAsync(requestUri, content))
{
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
res = JsonConvert.DeserializeObject<TokenResponseModel>(responseContent);
}
else
{
apiLog.Response = response;
}
}
由于数据传输过程中会干扰很多因素,因此可以根据当前情况的特殊性相应增加连接超时时间,以提高数据传输操作的成功率。
// PAYLOAD TO SEND TO THE RECEIVER
byte[] payload_to_send = new byte[2000000];
// CREATE THE HTTP CLIENT OBJECT
HttpClient client = new HttpClient();
// SET THE BASE ADDRESS OF THE HTTP CLIENT OBJECT
client.BaseAddress = new Uri(NavigationManager.BaseUri);
// CREATE A TEST PAYLOAD
byte[] test_payload = new byte[204800];
// SET THE CONTENT TO BE SENT AS A TEST PAYLOAD AS A BYTE ARRAY
ByteArrayContent http_payload = new ByteArrayContent(test_payload);
// CREATE A STOPWATCH OBJECT TO MONITOR THE TIME TOOK BY EACH DATA TRANSFER PROCESS
System.Diagnostics.Stopwatch latency_time_counter = new System.Diagnostics.Stopwatch();
// INTEGER THAT STORES HOW MANY BYTES PER SECOND TOOK TO TRANSFER THE TEST PAYLOAD
long download_bytes_per_second = 0;
// TRANSFER THE PAYLOAD 10 TIMES
for (int i = 0; i < 10; i++)
{
latency_time_counter.Start();
await client.PostAsync("/speed-test-api/auth/get-account", http_payload);
latency_time_counter.Stop();
// INCREMENT THE 'download_bytes_per_second' BY THE NUMBER OF BYTES PER SECOND TOOK TO TRANSFER THE PAYLOAD FOR EACH ITERATION
download_bytes_per_second += (long)(test_payload.Length * (1000 / latency_time_counter.Elapsed.TotalMilliseconds));
Console.WriteLine("Bytes per second: " + download_bytes_per_second);
latency_time_counter.Reset();
}
// DIVIDE THE TOTAL NUMBER OF BYTES PER SECOND BY THE NUMBER OF ITERATIONS TO GET THE AVERAGE BYTES PER SECOND
download_bytes_per_second = download_bytes_per_second / 10;
// ESTIMATION ERROR IN SECONDS
int timeout_rounding_error = 1;
// CALCULATE THE OPTIMAL TIMEOUT BASED ON THE LENGTH OF THE PAYLOAD TO BE SENT
long download_optimal_connection_timeout = (payload_to_send.Length / download_bytes_per_second) + timeout_rounding_error;
Console.WriteLine("\n\nAverage bytes per second: " + download_optimal_connection_timeout);
// SET THE CONNECTION TIMEOUT
client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(download_optimal_connection_timeout);
为了计算最佳数据传输超时,必须计算数据传输速度并相应设置超时。创建一个
HttpClient
对象,并循环向接收器发送 20 KB 的有效负载,同时测量每次迭代传输有效负载所需的毫秒数。计算方法是将有效负载中的字节数乘以 1000 毫秒,然后除以发送有效负载所需的总毫秒数。因为每秒的字节数是要提取的目标值,所以将 1000 除以总毫秒数即可得到每秒的比率,例如传输 1000 个字节所需的时间为 10 秒,则传输 1000 个字节的时间为 10 秒,则每秒字节数为 100,因为 10 秒比 1 大 10 倍,所以结果将为 0.1(表示 1 秒占总时间的 10%),并将有效负载中的总字节数乘以 0.1 得到结果每秒传输的总有效负载的 10%,从而得出以下公式: BPS = TPB * 1000 / TT,其中 BPS = 每秒字节数,TPB = 总负载字节数,以及 TT = 总时间。每次迭代,保存每秒字节数的速度的变量都会增加 TPB。迭代完成后,将保存每秒字节数的速度的变量除以 10,以获得每秒字节数的平均速度。然后,将要发送的有效负载的长度除以每秒字节数的速度,以获得要发送的数据将在多少秒内传输,并为该数字添加超时舍入误差,在本例中为一秒。您可以通过此链接找到其背后的数学原理和逻辑:https://www.baeldung.com/cs/calculate-internet-speed-ping