httpclient.GetAsync:底层连接已关闭:发送时发生意外错误

Bur*_*ort 1 c# asp.net-web-api

我有一个简单的 web api,它获取一个 url,并生成一个短数字作为短 url。我创建了一个 VS 控制台应用程序,我在其中通过HTTPClient对象调用 web api 。当我第一次运行代码时,它抛出以下错误:

错误消息: 发生了一个或多个错误。

内部异常: System.Net.Http.HttpRequestException:发送请求时出错。---> System.Net.WebException: 基础连接已关闭:发送时发生意外错误。---> System.IO.IOException: 无法从传输连接读取数据:远程主机强行关闭了现有连接。---> System.Net.Sockets.SocketException: 远程主机在 System.Net.Sockets.Sockets.Socket.EndReceive(IAsyncResult asyncResult) 处的 System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) 处强行关闭了现有连接--- 内部异常堆栈跟踪结束 --- 在 System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) 在 System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) --- 内部异常堆栈跟踪结束 --- 在 System .Net.HttpWebRequest。

这是我用来调用 web api 的代码。通过浏览器调用 web api 工作得很好。

static void Main(string[] args)
{
    string url = "https://app1/api/AddUrl?longUrl=http://google.com";
    var result = GetTinyUrl(url).Result;
    Console.WriteLine(result.ShortUrl);     
}

protected static async Task<UrlResponse> GetUrl(string baseUrl)
{
    HttpClientHandler handler = new HttpClientHandler();
    handler.UseDefaultCredentials = true;

    var client = new HttpClient(handler);

    var response = client.GetAsync(baseUrl).Result;
    if (response.IsSuccessStatusCode)
    {
        HttpResponseMessage response1 = response;
        response.EnsureSuccessStatusCode();
        var resp = await response.Content.ReadAsStringAsync();
        var result = JsonConvert.DeserializeObject<UrlResponse>(resp);
        return result;
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)

Ric*_*xon 12

只是说,在连接到我正在编写的天蓝色服务时,我花了几个小时研究类似的问题。

无法弄清楚为什么邮递员工作正常但我的代码却严重失败。同样,我在代码中尝试过的其他 URL 工作正常或出现预期的失败。

最后失败的原因是我忘记降低TLS/SSL 设置刀片中的最低 TLS 版本

我认为旧版本的 HttpClient 只能处理 TLS v1.0。

  • 被这个绊倒了,当我看到 TLS 时,一切又回来了: System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 为了胜利 (6认同)

Nko*_*osi 5

.Result阻塞调用与异步等待混合使用可能会导致死锁。

如果使用 async await 然后一直使用 async,并避免HttpClient为每个调用创建一个新的实例,因为这会导致 socked 耗尽。

static Lazy<HttpClient> http = new Lazy<HttpClient>(() => {
    //Handle TLS protocols
    System.Net.ServicePointManager.SecurityProtocol =
        System.Net.SecurityProtocolType.Tls
        | System.Net.SecurityProtocolType.Tls11
        | System.Net.SecurityProtocolType.Tls12;

    var handler = new HttpClientHandler() {
        UseDefaultCredentials = true
    };

    var client = new HttpClient(handler);
    return client;
});

protected static async Task<UrlResponse> GetUrl(string baseUrl) {
    var client = http.Value;

    var response = await client.GetAsync(baseUrl); //Remove .Result and just await
    if (response.IsSuccessStatusCode) {
        HttpResponseMessage response1 = response;
        response.EnsureSuccessStatusCode();
        var resp = await response.Content.ReadAsStringAsync();
        var result = JsonConvert.DeserializeObject<UrlResponse>(resp);
        return result;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

由于这是一个控制台应用程序并且只有一个线程然后调用异步,因此您必须更改在 main 中调用异步方法的方式

static void Main(string[] args) {
    string url = "https://app1/api/AddUrl?longUrl=http://google.com";
    var result = GetTinyUrl(url).GetAwaiter().GetResult(); //<-- 
    Console.WriteLine(result.ShortUrl);     
}
Run Code Online (Sandbox Code Playgroud)

参考Async/Await - 异步编程的最佳实践