httpclient.GetAsync:基础连接已关闭:发送中发生意外错误

时间:2019-01-08 10:29:15

标签: c# asp.net-web-api

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

  

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

     

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

这是我用来调用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;
}

4 个答案:

答案 0 :(得分:1)

.Result混合使用异步等待阻塞呼叫可能导致死锁。

如果使用异步等待,则要一直保持异步,并避免为每个调用创建HttpClient的新实例,因为这可能会导致精疲力尽。

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

由于这是一个控制台应用程序,只有一个线程然后调用async,所以您必须更改在main中调用async方法的方式

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

引用Async/Await - Best Practices in Asynchronous Programming

答案 1 :(得分:0)

我通常不建议使用HttpClient来处理Web请求,因为它有时可能会与各种Web API行为不符。我强烈建议您改用HttpWebRequest。您可以在完全控制的情况下适当地设计HTTP请求,这样会产生更好的总体结果。

string uri = "https://api.foo.com/bar";

var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET"; // PUT, POST, DELETE, etc
//httpWebRequest.ContentLength = 0; // sometimes you need to send zero (depending on API)
HttpWebResponse httpResponse = (HttpWebResponse)await httpWebRequest.GetResponseAsync();

using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var response = streamReader.ReadToEnd();
    // this is your code here...
    var result = JsonConvert.DeserializeObject<UrlResponse>(response);
    return result;
}

答案 2 :(得分:0)

可以说,当我连接到正在编写的Azure服务时,我花费了数小时来研究类似的问题。

无法弄清楚为什么邮递员工作得很好,但是我的代码却失败了。同样,我在代码中尝试过的其他URL也可以正常工作或出现了预期的故障。

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

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

答案 3 :(得分:0)

在解决方案属性中选择更高的目标框架解决了我的问题。