<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
        Go to my github

      【譯】.NET 8 網絡改進(一)

      原文 | Máňa,Natalia Kondratyeva

      翻譯 | 鄭子銘

      隨著新的 .NET 版本的發布,發布有關網絡空間中新的有趣變化的博客文章已成為一種傳統。今年,我們希望引入 HTTP 空間的變化、新添加的指標、新的 HttpClientFactory API 等。

      HTTP協議

      指標

      .NET 8 使用 .NET 6 中引入的 System.Diagnostics.Metrics API 將內置 HTTP 指標添加到 ASP.NET Core 和 HttpClient。指標 API 和新內置指標的語義都是在與 OpenTelemetry 密切合作,確保新指標符合標準,并與 PrometheusGrafana 等流行工具良好配合。

      System.Diagnostics.Metrics API 引入了許多 EventCounters 所缺少的新功能。新的內置指標廣泛利用了這些功能,從而通過更簡單、更優雅的儀器集實現了更廣泛的功能。舉幾個例子:

      • 直方圖使我們能夠報告持續時間,例如。請求持續時間 (http.client.request.duration) 或連接持續時間 (http.client.connection.duration)。這些是沒有 EventCounter 對應項的新指標。
      • 多維性允許我們將標簽(又名屬性或標簽)附加到測量值上,這意味著我們可以報告諸如 server.address (標識 URI 來源)或 error.type (描述請求失敗時的錯誤原因)之類的信息測量值。多維還可以實現簡化:報告打開的 HTTP 連接數 SocketsHttpHandler 使用 3 個 EventCounters:http11-connections-current-total、http20-connections-current-total 和 http30-connections-current-total,而 Metrics 相當于這些counters 是一個單一的工具,http.client.open_connections,其中 HTTP 版本是使用 network.protocol.version 標簽報告的。
      • 為了幫助內置標簽不足以對傳出 HTTP 請求進行分類的用例,http.client.request.duration 指標支持注入用戶定義的標簽。這稱為濃縮
      • IMeterFactory 集成可以隔離用于發出 HTTP 指標的 Meter 實例,從而更輕松地編寫針對內置測量運行驗證的測試,并實現此類測試的并行執行。
      • 雖然這并不是特定于內置網絡指標,但值得一提的是 System.Diagnostics.Metrics 中的集合 API 也更高級:它們是強類型的且性能更高,并允許多個同時偵聽器和偵聽器訪問未聚合的測量結果。

      這些優勢共同帶來了更好、更豐富的指標,這些指標可以通過 Prometheus 等第三方工具更有效地收集。得益于 PromQL(Prometheus 查詢語言)的靈活性,它允許針對從 .NET 網絡堆棧收集的多維指標創建復雜的查詢,用戶現在可以深入了解 HttpClient 和 SocketsHttpHandler 實例的狀態和運行狀況,其級別如下:以前是不可能的。

      不利的一面是,我們應該提到,.NET 8 中只有 System.Net.Http 和 System.Net.NameResolution 組件使用 System.Diagnostics.Metrics 進行檢測,這意味著您仍然需要使用 EventCounters 從較低層提取計數器堆棧的級別,例如 System.Net.Sockets。雖然仍然支持以前版本中存在的所有內置 EventCounters,但 .NET 團隊預計不會對 EventCounters 進行大量新投資,并且在未來版本中將使用 System.Diagnostics.Metrics 添加新的內置檢測。

      有關使用內置 HTTP 指標的更多信息,請閱讀我們有關 .NET 中的網絡指標的教程。它包括有關使用 Prometheus 和 Grafana 進行收集和報告的示例,還演示了如何豐富和測試內置 HTTP 指標。有關內置工具的完整列表,請參閱 System.Net 指標的文檔。如果您對服務器端更感興趣,請閱讀有關 ASP.NET Core 指標的文檔。

      擴展遙測

      除了新指標之外,.NET 5 中引入的現有基于 EventSource 的遙測事件還增加了有關 HTTP 連接的更多信息 (dotnet/runtime#88853):

      - ConnectionEstablished(byte versionMajor, byte versionMinor)
      + ConnectionEstablished(byte versionMajor, byte versionMinor, long connectionId, string scheme, string host, int port, string? remoteAddress)
      
      - ConnectionClosed(byte versionMajor, byte versionMinor)
      + ConnectionClosed(byte versionMajor, byte versionMinor, long connectionId)
      
      - RequestHeadersStart()
      + RequestHeadersStart(long connectionId)
      

      現在,當建立新連接時,該事件會記錄其連接 ID 及其方案、端口和對等 IP 地址。這使得可以通過 RequestHeadersStart 事件將請求和響應與連接關聯起來(當請求關聯到池連接并開始處理時發生),該事件還記錄關聯的 ConnectionId。這在用戶想要查看為其 HTTP 請求提供服務的服務器的 IP 地址的診斷場景中尤其有價值,這是添加項背后的主要動機 (dotnet/runtime#63159)。

      事件可以通過多種方式使用,請參閱.NET 中的網絡遙測 – 事件。但為了進程內增強日志記錄,可以使用自定義 EventListener 將請求/響應對與連接數據相關聯:

      using IPLoggingListener ipLoggingListener = new();
      using HttpClient client = new();
      
      // Send requests in parallel.
      await Parallel.ForAsync(0, 1000, async (i, ct) =>
      {
          // Initialize the async local so that it can be populated by "RequestHeadersStart" event handler.
          RequestInfo info = RequestInfo.Current;
          using var response = await client.GetAsync("https://testserver");
          Console.WriteLine($"Response {response.StatusCode} handled by connection {info.ConnectionId}. Remote IP: {info.RemoteAddress}");
      
          // Process response...
      });
      
      internal sealed class RequestInfo
      {
          private static readonly AsyncLocal<RequestInfo> _asyncLocal = new();
          public static RequestInfo Current => _asyncLocal.Value ??= new();
      
          public string? RemoteAddress;
          public long ConnectionId;
      }
      
      internal sealed class IPLoggingListener : EventListener
      {
          private static readonly ConcurrentDictionary<long, string> s_connection2Endpoint = new ConcurrentDictionary<long, string>();
      
          // EventId corresponds to [Event(eventId)] attribute argument and the payload indices correspond to the event method argument order.
      
          // See: https://github.com/dotnet/runtime/blob/a6e4834d53ac591a4b3d4a213a8928ad685f7ad8/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs#L100-L101
          private const int ConnectionEstablished_EventId = 4;
          private const int ConnectionEstablished_ConnectionIdIndex = 2;
          private const int ConnectionEstablished_RemoteAddressIndex = 6;
      
          // See: https://github.com/dotnet/runtime/blob/a6e4834d53ac591a4b3d4a213a8928ad685f7ad8/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs#L106-L107
          private const int ConnectionClosed_EventId = 5;
          private const int ConnectionClosed_ConnectionIdIndex = 2;
      
          // See: https://github.com/dotnet/runtime/blob/a6e4834d53ac591a4b3d4a213a8928ad685f7ad8/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs#L118-L119
          private const int RequestHeadersStart_EventId = 7;
          private const int RequestHeadersStart_ConnectionIdIndex = 0;
      
          protected override void OnEventSourceCreated(EventSource eventSource)
          {
              if (eventSource.Name == "System.Net.Http")
              {
                  EnableEvents(eventSource, EventLevel.LogAlways);
              }
          }
      
          protected override void OnEventWritten(EventWrittenEventArgs eventData)
          {
              ReadOnlyCollection<object?>? payload = eventData.Payload;
              if (payload == null) return;
      
              switch (eventData.EventId)
              {
                  case ConnectionEstablished_EventId:
                      // Remember the connection data.
                      long connectionId = (long)payload[ConnectionEstablished_ConnectionIdIndex]!;
                      string? remoteAddress = (string?)payload[ConnectionEstablished_RemoteAddressIndex];
                      if (remoteAddress != null)
                      {
                          Console.WriteLine($"Connection {connectionId} established to {remoteAddress}");
                          s_connection2Endpoint.TryAdd(connectionId, remoteAddress);
                      }
                      break;
                  case ConnectionClosed_EventId:
                      connectionId = (long)payload[ConnectionClosed_ConnectionIdIndex]!;
                      s_connection2Endpoint.TryRemove(connectionId, out _);
                      break;
                  case RequestHeadersStart_EventId:
                      // Populate the async local RequestInfo with data from "ConnectionEstablished" event.
                      connectionId = (long)payload[RequestHeadersStart_ConnectionIdIndex]!;
                      if (s_connection2Endpoint.TryGetValue(connectionId, out remoteAddress))
                      {
                          RequestInfo.Current.RemoteAddress = remoteAddress;
                          RequestInfo.Current.ConnectionId = connectionId;
                      }
                      break;
              }
          }
      }
      

      此外,重定向事件已擴展為包含重定向 URI:

      -void Redirect();
      +void Redirect(string redirectUri);
      

      HTTP 錯誤代碼

      HttpClient 的診斷問題之一是,在發生異常時,不容易以編程方式區分錯誤的確切根本原因。區分其中許多的唯一方法是解析來自 HttpRequestException 的異常消息。此外,其他 HTTP 實現(例如帶有 ERROR_WINHTTP_* 錯誤代碼的 WinHTTP)以數字代碼或枚舉的形式提供此類功能。因此.NET 8引入了類似的枚舉,并在HTTP處理拋出的異常中提供它,它們是:

      dotnet/runtime#76644 API 提案中描述了 HttpRequestError 枚舉的設計以及如何將其插入 HTTP 異常。

      現在,HttpClient 方法的使用者可以更輕松、更可靠地處理特定的內部錯誤:

      using HttpClient httpClient = new();
      
      // Handling problems with the server:
      try
      {
          using HttpResponseMessage response = await httpClient.GetAsync("https://testserver", HttpCompletionOption.ResponseHeadersRead);
          using Stream responseStream = await response.Content.ReadAsStreamAsync();
          // Process responseStream ...
      }
      catch (HttpRequestException e) when (e.HttpRequestError == HttpRequestError.NameResolutionError)
      {
          Console.WriteLine($"Unknown host: {e}");
          // --> Try different hostname.
      }
      catch (HttpRequestException e) when (e.HttpRequestError == HttpRequestError.ConnectionError)
      {
          Console.WriteLine($"Server unreachable: {e}");
          // --> Try different server.
      }
      catch (HttpIOException e) when (e.HttpRequestError == HttpRequestError.InvalidResponse)
      {
          Console.WriteLine($"Mangled responses: {e}");
          // --> Block list server.
      }
      
      // Handling problems with HTTP version selection:
      try
      {
          using HttpResponseMessage response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://testserver")
          {
              Version = HttpVersion.Version20,
              VersionPolicy = HttpVersionPolicy.RequestVersionExact
          }, HttpCompletionOption.ResponseHeadersRead);
          using Stream responseStream = await response.Content.ReadAsStreamAsync();
          // Process responseStream ...
      }
      catch (HttpRequestException e) when (e.HttpRequestError == HttpRequestError.VersionNegotiationError)
      {
          Console.WriteLine($"HTTP version is not supported: {e}");
          // Try with different HTTP version.
      }
      

      HTTPS 代理支持

      此版本實現的最受歡迎的功能之一是支持 HTTPS 代理 (dotnet/runtime#31113)。現在可以使用代理通過 HTTPS 處理請求,這意味著與代理的連接是安全的。這并沒有說明來自代理的請求本身,它仍然可以是 HTTP 或 HTTPS。如果是純文本 HTTP 請求,與 HTTPS 代理的連接是安全的(通過 HTTPS),然后是從代理到目標的純文本請求。如果是 HTTPS 請求(代理隧道),打開隧道的初始 CONNECT 請求將通過安全通道 (HTTPS) 發送到代理,然后通過隧道將 HTTPS 請求從代理發送到目的地。

      要利用該功能,只需在設置代理時使用 HTTPS 方案即可:

      using HttpClient client = new HttpClient(new SocketsHttpHandler()
      {
          Proxy = new WebProxy("https://proxy.address:12345")
      });
      
      using HttpResponseMessage response = await client.GetAsync("https://httpbin.org/");
      

      HttpClientFactory

      .NET 8 擴展了配置 HttpClientFactory 的方式,包括客戶端默認設置、自定義日志記錄和簡化的 SocketsHttpHandler 配置。這些 API 在 Microsoft.Extensions.Http 包中實現,該包可在 NuGet 上獲取,并包含對 .NET Standard 2.0 的支持。因此,此功能不僅適用于 .NET 8 上的客戶,而且適用于所有版本的 .NET,包括 .NET Framework(唯一的例外是僅適用于 .NET 5+ 的 SocketsHttpHandler 相關 API)。

      為所有客戶端設置默認值

      .NET 8 添加了設置默認配置的功能,該配置將用于 HttpClientFactory (dotnet/runtime#87914) 創建的所有 HttpClient。當所有或大多數注冊客戶端包含相同的配置子集時,這非常有用。

      考慮一個定義了兩個命名客戶端的示例,并且它們的消息處理程序鏈中都需要 MyAuthHandler。

      services.AddHttpClient("consoto", c => c.BaseAddress = new Uri("https://consoto.com/"))
          .AddHttpMessageHandler<MyAuthHandler>();
      
      services.AddHttpClient("github", c => c.BaseAddress = new Uri("https://github.com/"))
          .AddHttpMessageHandler<MyAuthHandler>();
      

      要提取公共部分,您現在可以使用ConfigureHttpClientDefaults方法:

      services.ConfigureHttpClientDefaults(b => b.AddHttpMessageHandler<MyAuthHandler>());
      
      // both clients will have MyAuthHandler added by default
      services.AddHttpClient("consoto", c => c.BaseAddress = new Uri("https://consoto.com/"));
      services.AddHttpClient("github", c => c.BaseAddress = new Uri("https://github.com/"));
      

      與 AddHttpClient 一起使用的所有 IHttpClientBuilder 擴展方法也可以在 ConfigureHttpClientDefaults 中使用。

      默認配置 (ConfigureHttpClientDefaults) 在客戶端特定 (AddHttpClient) 配置之前應用于所有客戶端;他們在注冊中的相對位置并不重要。配置HttpClientDefaults可以注冊多次,在這種情況下,配置將按照注冊的順序一一應用。配置的任何部分都可以在特定于客戶端的配置中覆蓋或修改,例如,您可以為 HttpClient 對象或主處理程序設置其他設置,刪除以前添加的其他處理程序等。

      請注意,從 8.0 開始,ConfigureHttpMessageHandlerBuilder 方法已被棄用。您應該改用ConfigurePrimaryHttpMessageHandler(Action<HttpMessageHandler,IServiceProvider>)ConfigureAdditionalHttpMessageHandlers 方法來分別修改先前配置的主處理程序或附加處理程序列表。

      // by default, adds User-Agent header, uses HttpClientHandler with UseCookies=false
      // as a primary handler, and adds MyAuthHandler to all clients
      services.ConfigureHttpClientDefaults(b =>
          b.ConfigureHttpClient(c => c.DefaultRequestHeaders.UserAgent.ParseAdd("HttpClient/8.0"))
           .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false })
           .AddHttpMessageHandler<MyAuthHandler>());
      
      // HttpClient will have both User-Agent (from defaults) and BaseAddress set
      // + client will have UseCookies=false and MyAuthHandler from defaults
      services.AddHttpClient("modify-http-client", c => c.BaseAddress = new Uri("https://httpbin.org/"))
      
      // primary handler will have both UseCookies=false (from defaults) and MaxConnectionsPerServer set
      // + client will have User-Agent and MyAuthHandler from defaults
      services.AddHttpClient("modify-primary-handler")
          .ConfigurePrimaryHandler((h, _) => ((HttpClientHandler)h).MaxConnectionsPerServer = 1);
      
      // MyWrappingHandler will be inserted at the top of the handlers chain
      // + client will have User-Agent, UseCookies=false and MyAuthHandler from defaults
      services.AddHttpClient("insert-handler-into-chain"))
          .ConfigureAdditionalHttpMessageHandlers((handlers, _) =>
              handlers.Insert(0, new MyWrappingHandler());
      
      // MyAuthHandler (initially from defaults) will be removed from the handler chain
      // + client will still have User-Agent and UseCookies=false from defaults
      services.AddHttpClient("remove-handler-from-chain"))
          .ConfigureAdditionalHttpMessageHandlers((handlers, _) =>
              handlers.Remove(handlers.Single(h => h is MyAuthHandler)));
      

      原文鏈接

      .NET 8 Networking Improvements

      知識共享許可協議

      本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

      歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: http://www.rzrgm.cn/MingsonZheng/ ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布。

      如有任何疑問,請與我聯系 (MingsonZheng@outlook.com)

      posted @ 2024-02-11 00:45  鄭子銘  閱讀(680)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品爽爽va在线观看网站| 九九热在线视频免费播放| 日韩大片一区二区三区| 国产成人毛片无码视频软件 | 东京热人妻无码一区二区av| 精品国产乱弄九九99久久| 国产亚洲精品AA片在线播放天 | 免费 黄 色 人成 视频 在 线| 免费人成视频在线观看不卡| 美女人妻激情乱人伦| 国产精品综合av一区二区| 国产人妇三级视频在线观看| 久久久久国产精品熟女影院 | 亚洲伊人成无码综合网| 亚洲无av中文字幕在线| 精品无码国产日韩制服丝袜| 国产精品一区二区香蕉| 国精品午夜福利不卡视频| 99久久亚洲综合精品成人网| 久久综合色之久久综合| 欧美丰满熟妇性xxxx| 九九热精品在线免费视频| 国产精品va在线观看无码| 色综合久久婷婷88| 高清国产亚洲精品自在久久| 超清无码一区二区三区| 亚洲首页一区任你躁xxxxx| 国产成人综合网亚洲第一| 色九九视频| 国产视频 视频一区二区| 中文字幕人妻精品在线| 四虎国产精品永久在线国在线| 国产精品一区二区不卡91| 中文字幕国产在线精品| 全黄h全肉边做边吃奶视频| 中文字幕无码成人免费视频| 国产精品中文字幕综合| 国产口爆吞精在线视频2020版| 亚洲国产成人久久综合一区77 | 久久精品国产亚洲av亚| 毛片av中文字幕一区二区|