我有一个简单的网络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;
}
答案 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);
}
答案 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)
在解决方案属性中选择更高的目标框架解决了我的问题。