C# 中 Timeout 的处理
前言
最近在项目中要实现一个功能,是关于 Timeout
的,主要是要在要在 TCP 连接建立的时间 和 整个请求完成的时间,在这两个时间层面上,如果超出了设置的时间,就抛出异常,程序中断。
研究了一下项目的代码中,发现在使用HTTP协议,发送请求时,主要用的是微软的 Microsoft.Net.HttpWebRequest
这个类来发起请求和接收请求的。当时我隐约记得这个类怎么有点熟悉呀,好像还有 WebRequst
和 HttpClient
这两个把,还没开始真正开始去了解Timeout
在HttpWebRequest
中 如何实现的,我先去看了看这三者到底有何不同?
WebRequest , HttpWebRequest , HttpClient
WebRequest 是 一个抽象类,是HttpWebRequest
的父类。是.NET
中请求和获取网络中的数据的一个类。
HttpWebRequest 是WebReques
t 的一个实现,不仅对WebRequest
中的属性和方法进行了支持,而且还有额外的方法通过Http
协议来和服务端交互。
上面那两个现在在微软官方文档上都不推荐使用了,
现在所推荐的是 HttpClient
。由于项目中遗留之前使用的是HttpWebRequest
,所以就在原来的基础上进行实现,何况的是在HttpClient
中没有找到TCP
连接建立的时间属性的设定。
HttpClient 优点自不必多说:
- 连接池
- 一次初始化,整个生命周期的重用
- 和 .Net Core 的融合
- 以及性能的提升等等
虽然说性能可能提升了,如果你这样用,那也是凉凉
using(HttpClient clinet = new HttpClient())
{
var result = await client.GetAsync("http://aspnetmonsters.com");
Console.WriteLine(result.StatusCode);
}
用完 Using
后,调用了IDispose
接口。那下次还是会重新初始化
这样使用就没问题了
private static HttpClient Client = new HttpClient();
Timeout, ReadWriteTimeout
也可能是我英文的理解能力有点差,在开始我就注意到这个类里面的这两个属性,但是我如何也无法和 TCP 建立前所用的连接时间 与 请求完成的时间联系起来。微软官方文档解释如下:
Timeout:
ReadWriteTimeout:
设置其实是很方便的,如下所示:
HttpWebRequest request = (HttpWebRequest)WebRequest.Creat("<your url>");
//Set timeout to 1s
request.Timeout = 1000;
//Set ReadWriteTimeout to 3000
request.ReadWriteTimeout = 3000;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
WebClient.Exception.Timeout 和 OperationCanceledException
最后在捕捉异常的时候,发现了一个很奇怪的地方,就是使用两段代码,却抛出了不同的异常,
第一段代码:
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("https://www.alibabacloud.com");
request.Timeout = 5000;
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
HttpWebRequest request2 = (HttpWebRequest) WebRequest.Create("https://www.cnblogs.com");
request2.Timeout = 1;
HttpWebResponse response2 = (HttpWebResponse) request2.GetResponse();
//Exception
/*
Unhandled Exception: System.Net.WebException: The operation has timed out.
at System.Net.HttpWebRequest.GetResponse()
*/
第二段
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("https://www.alibabacloud.com");
request.Timeout = 5000;
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
request = (HttpWebRequest) WebRequest.Create("https://www.cnblogs.com");
request.Timeout = 1;
response = (HttpWebResponse) request.GetResponse();
//Exception
/*
Unhandled Exception: System.OperationCanceledException: The operation was canceled.
at System.Net.HttpWebRequest.GetResponse()
*/
初步估计的原因是,Http 请求中 Keep-Alive的关系,还有一个可能是 Timeout 的这个说明:
The Timeout applies to the entire request and response, not individually to the GetRequestStream and GetResponse method calls. 然而具体的还没搞清楚,还需要去验证。
后记
其实,设置这两个属性你可能只需要找到文档,分分钟就可以搞定,但是我为什么会在这个过程遇到这些问题呢?一方面是对于C# 中网络请求的不熟悉,其次是找个时间,把以前的代码需要重构一下了,比如把HttpWebRequest
换成 HttpClient
等等。也让我加深了对Http协议
的理解。