【发布时间】:2020-06-26 08:04:07
【问题描述】:
我开发了 C# .net 4.6.1 应用程序(这是Windows Service Application)。在应用程序中,我使用 HttpClient 与我们的后端 API 进行通信。随着时间的推移,应用程序不会向我们的后端发送请求(TaskCanceledException 被捕获)。
这里是这个异常的堆栈跟踪
System.Threading.Tasks.TaskCanceledException · 任务被取消。
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
TestHttpClient+<GetRequestAsync>d__20.MoveNext()
这个问题有两个原因解决
- 重启应用后
- 重复尝试相同的请求时
我使用Fiddler 调查了这个问题,当异常发生且处于正常状态时
In normal mode fiddler shows 2 requests
- Result=200,Protocol=HTTP,Host = Tunnel to,Url = api.example.com:443
在 SyntaxView 选项卡中:找到了与 SSLv3 兼容的 ClientHello 握手。 Fiddler 提取了以下参数。
- 结果 = 200,协议 = HTTPS,主机 = api.example.com,网址 = /test
In failed mode Fiddler shows only 1 requst
- Result=200,Protocol=HTTP,Host = Tunnel to,Url = api.example.com:443,
在 SyntaxView 选项卡中: 客户收到通知后 建立CONNECT,发送数据失败
这是我们代码的 sn-p。
class Program
{
static void Main(string[] args)
{
// I Tried also without Task.Run() i.e. MyClass myClass = GetAsync().Result;
MyClass myClass = Task.Run(() => GetAsync().Result).Result ;
}
private static async Task<MyClass> GetAsync()
{
// I Tried also without .ConfigureAwait(false)
MyClassResponse myClassResponse = await TestHttpClient.GetMyClassResponse().ConfigureAwait(false);
return MyClass.Create(myClassResponse);
}
}
public static class TestHttpClient
{
private static HttpClient _httpClient;
public static void Init()
{
ServicePointManager.SecurityProtocol |= (SecurityProtocolType.Ssl3 |
SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls);
ServicePointManager.DefaultConnectionLimit = 10;
_httpClient = CreateHttpClient();
}
private static HttpClient CreateHttpClient()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token .....");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromMilliseconds(10000);
return client;
}
public static async Task<MyClassResponse> GetMyClassResponse()
{
HttpResponseMessage response = await GetRequestAsync("https://api.example.com/test");
return await ParseToMyClassResponse<MyClassResponse>(response);
}
private static async Task<HttpResponseMessage> GetRequestAsync(string url)
{
try
{
return await _httpClient.GetAsync(new Uri(url));
}
catch (TaskCanceledException)
{
return new HttpResponseMessage(HttpStatusCode.RequestTimeout);
}
}
private static async Task<T> ParseToMyClassResponse<T>(HttpResponseMessage response) where T : MyClassResponse, new()
{
T myClassResponse;
try
{
string content = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
myClassResponse = JsonConvert.DeserializeObject<T>(content);
}
catch (Exception ex)
{
myClassResponse = new T();
}
response.Dispose();
return myClassResponse;
}
}
我做错了什么?
为什么Fiddler 显示"After the client received notice of the established CONNECT, it failed to send any data" 消息。
【问题讨论】:
-
你不应该再使用
SecurityProtocolType.Ssl3。 SSLv3 严重不安全且过时。大多数服务器甚至不再支持 SSLv3 客户端 hello。 -
嗨@罗伯特。感谢您的快速回复。我们有一个
System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel。添加SecurityProtocolType.Ssl3后,异常消失了。如果异常与SecurityProtocolType.Ssl3有关,那么为什么有时会发生这种情况。 -
服务器是 Internet 上的公共服务器还是您的 Intranet 中的私有服务器?如果您在控制服务器,则应检查它,因为如果它需要 SSLv3 握手,则非常不安全。我认为这也是 Fiddler 的问题。根据使用的 Windows 版本,Fiddler 也不使用 SSLv3 握手,因此无法建立与服务器的连接。
-
@Robert 服务器是公开的。在服务器上我们使用
TLS。我不知道为什么,但没有SecurityProtocolType.Ssl3我们有System.Net.WebException异常。我想指出System.Net.WebException异常并不总是发生。好的,我会尝试删除SecurityProtocolType.Ssl3,如果System.Net.WebException异常会再次出现。我会开启一个新的讨论。你能解释一下为什么这个错误并不总是发生吗? -
如果他的服务器是公开的,我建议对其执行 SSL 测试:ssllabs.com/ssltest 另外请记住,对于 Dot.net 程序,使用的是 Windows 的 SSL/TLS 实现。因此,如果您使用过时的操作系统,如 Win7 或 XP,它可能会因为操作系统而失败。
标签: c# .net async-await fiddler dotnet-httpclient