.Net5下WebRequest、WebClient、HttpClient是否還存在使用爭議?
WebRequest、WebClient、HttpClient 是C#中常用的三個Http請求的類,時不時也會有人發表對這三個類使用場景的總結,本人是HttpClient 一把梭,也沒太關注它們的內部實現,最近比較閑就看了下它們內部實現到底有什麼差別。
WebClient其實就是對WebRequest的二次封裝,便於使用。所以主要看WebRequest和HttpClient之間的差別。WebRequest的默認實現是HttpWebRequest。我把其中關於今天主題關鍵的程式碼貼出來:
1 public override WebResponse GetResponse() 2 { 3 try 4 { 5 _sendRequestCts = new CancellationTokenSource(); 6 return SendRequest(async: false).GetAwaiter().GetResult(); 7 } 8 catch (Exception ex) 9 { 10 throw WebException.CreateCompatibleException(ex); 11 } 12 }
1 private async Task<WebResponse> SendRequest(bool async) 2 { 3 if (RequestSubmitted) 4 { 5 throw new InvalidOperationException(SR.net_reqsubmitted); 6 } 7 8 var request = new HttpRequestMessage(new HttpMethod(_originVerb), _requestUri); 9 10 bool disposeRequired = false; 11 HttpClient? client = null; 12 try 13 { 14 client = GetCachedOrCreateHttpClient(async, out disposeRequired); 15 if (_requestStream != null) 16 { 17 ArraySegment<byte> bytes = _requestStream.GetBuffer(); 18 request.Content = new ByteArrayContent(bytes.Array!, bytes.Offset, bytes.Count); 19 } 20 21 if (_hostUri != null) 22 { 23 request.Headers.Host = Host; 24 } 25 26 // Copy the HttpWebRequest request headers from the WebHeaderCollection into HttpRequestMessage.Headers and 27 // HttpRequestMessage.Content.Headers. 28 foreach (string headerName in _webHeaderCollection) 29 { 30 // The System.Net.Http APIs require HttpRequestMessage headers to be properly divided between the request headers 31 // collection and the request content headers collection for all well-known header names. And custom headers 32 // are only allowed in the request headers collection and not in the request content headers collection. 33 if (IsWellKnownContentHeader(headerName)) 34 { 35 if (request.Content == null) 36 { 37 // Create empty content so that we can send the entity-body header. 38 request.Content = new ByteArrayContent(Array.Empty<byte>()); 39 } 40 41 request.Content.Headers.TryAddWithoutValidation(headerName, _webHeaderCollection[headerName!]); 42 } 43 else 44 { 45 request.Headers.TryAddWithoutValidation(headerName, _webHeaderCollection[headerName!]); 46 } 47 } 48 49 request.Headers.TransferEncodingChunked = SendChunked; 50 51 if (KeepAlive) 52 { 53 request.Headers.Connection.Add(HttpKnownHeaderNames.KeepAlive); 54 } 55 else 56 { 57 request.Headers.ConnectionClose = true; 58 } 59 60 request.Version = ProtocolVersion; 61 62 _sendRequestTask = async ? 63 client.SendAsync(request, _allowReadStreamBuffering ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead, _sendRequestCts!.Token) : 64 Task.FromResult(client.Send(request, _allowReadStreamBuffering ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead, _sendRequestCts!.Token)); 65 66 HttpResponseMessage responseMessage = await _sendRequestTask.ConfigureAwait(false); 67 68 HttpWebResponse response = new HttpWebResponse(responseMessage, _requestUri, _cookieContainer); 69 70 int maxSuccessStatusCode = AllowAutoRedirect ? 299 : 399; 71 if ((int)response.StatusCode > maxSuccessStatusCode || (int)response.StatusCode < 200) 72 { 73 throw new WebException( 74 SR.Format(SR.net_servererror, (int)response.StatusCode, response.StatusDescription), 75 null, 76 WebExceptionStatus.ProtocolError, 77 response); 78 } 79 80 return response; 81 } 82 finally 83 { 84 if (disposeRequired) 85 { 86 client?.Dispose(); 87 } 88 } 89 }
在SendRequest(bool async)方法中調用了一個方法GetCachedOrCreateHttpClient看到此處我一陣感慨,最終還是調用了HttpClient。到此也能粗顯的看出來,三者在.Net5下,本質已經沒有了區別,只是對外的表現形式不同而已,使用了時候不必太糾結內部實現優先不同,只關注自己喜歡怎麼樣的寫法就行了。