从Web应用程序调用外部API时如何处理不一致的HttpRequestExceptions

问题描述 投票:0回答:1

在后台尝试使用

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;
    }
}

知道如何解决这些问题吗?

c# .net sockets httpclient port
1个回答
0
投票

拓扑

HTTP/HTTPS 是基于 TCP/IP 网络协议构建的网络协议。 TCP/IP 协议使用 SYNACKSYN/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

结果

Image with the result of the timeout calculation

© www.soinside.com 2019 - 2024. All rights reserved.