1. 程式人生 > >C# .net 中 Timeout 的處理及遇到的問題

C# .net 中 Timeout 的處理及遇到的問題

throws read was 了解 額外 開始 write .cn ati

C# 中 Timeout 的處理

前言

最近在項目中要實現一個功能,是關於 Timeout 的,主要是要在要在 TCP 連接建立的時間 和 整個請求完成的時間,在這兩個時間層面上,如果超出了設置的時間,就拋出異常,程序中斷。

研究了一下項目的代碼中,發現在使用HTTP協議,發送請求時,主要用的是微軟的 Microsoft.Net.HttpWebRequest 這個類來發起請求和接收請求的。當時我隱約記得這個類怎麽有點熟悉呀,好像還有 WebRequstHttpClient 這兩個把,還沒開始真正開始去了解TimeoutHttpWebRequest中 如何實現的,我先去看了看這三者到底有何不同?

WebRequest , HttpWebRequest , HttpClient

WebRequest 是 一個抽象類,是HttpWebRequest 的父類。是.NET中請求和獲取網絡中的數據的一個類。

HttpWebRequest 是WebRequest 的一個實現,不僅對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

Timeout is the number of milliseconds that a subsequent synchronous request made with the GetResponse method waits for a response, and the GetRequestStream method waits for a stream. The Timeout applies to the entire request and response, not individually to the GetRequestStream and GetResponse method calls. If the resource is not returned within the time-out period, the request throws a WebException with the Status property set to WebExceptionStatus.Timeout.

The Timeout property has no effect on asynchronous requests made with the BeginGetResponse or BeginGetRequestStream method.

ReadWriteTimeout:

The ReadWriteTimeout property is used when writing to the stream returned by the GetRequestStream method or reading from the stream returned by the GetResponseStream method.

Specifically, the ReadWriteTimeout property controls the time-out for the Read method, which is used to read the stream returned by the GetResponseStream method, and for the Write method, which is used to write to the stream returned by the GetRequestStream method.

設置其實是很方便的,如下所示:

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協議的理解。

C# .net 中 Timeout 的處理及遇到的問題