Покращення роботи з мережею в .NET 8
Вже стало традицією публікувати в блозі повідомлення про нові цікаві зміни в мережевому просторі з новим випуском .NET . Цього року ми хотіли б запровадити зміни в просторі HTTP , нові додані метрики, нові API HttpClientFactory, тощо.
HTTP
Метрики
.NET 8 додає вбудовані HTTP-метрики як до ASP.NET Core, так і до HttpClient, за допомогою System.Diagnostics.Metrics API, який був представлений у .NET 6. І API-інтерфейси Metrics, і семантика нових вбудованих показників були розроблені у тісній співпраці з OpenTelemetry, переконуючись, що нові показники відповідають стандарту та добре працюють із такими популярними інструментами, як Prometheus і Grafana. .
API System.Diagnostics.Metrics представляє багато нових функцій, яких не було в 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 є одним інструментом, http.client.open_connections, де версія HTTP повідомляється за допомогою тегу network.protocol.version.
– Щоб допомогти використати випадки, коли вбудованих тегів недостатньо для класифікації вихідних HTTP-запитів, метрика http.client.request.duration підтримує впровадження тегів, визначених користувачем. Це називається збагаченням.
– Інтеграція IMeterFactory дозволяє ізолювати екземпляри Meter, які використовуються для випромінювання метрик HTTP, що полегшує написання тестів, які перевіряють вбудовані вимірювання, і дозволяє паралельне виконання таких тестів.
– Хоча це не стосується вбудованих мережевих метрик, варто зазначити, що API колекції System.Diagnostics.Metrics також є більш досконалими: вони суворо типізовані та більш продуктивні та відкривають кільком слухачам одночасно доступ до неагрегованих вимірювань.
Ці переваги разом призводять до кращих, багатших показників, які можна ефективніше збирати сторонніми інструментами, такими як Prometheus. Завдяки гнучкості PromQL (Prometheus Query Language) , яка дозволяє створювати складні запити на основі багатовимірних показників, зібраних із мережевого стеку .NET, користувачі тепер можуть отримувати статистичні дані про стан і працездатність екземплярів HttpClient та SocketsHttpHandler на рівні, який не був раніше можливим.
З іншого боку, слід зазначити, що лише компоненти System.Net.Http та System.Net.NameResolution інструментуються за допомогою System.Diagnostics.Metrics у .NET 8, а це означає, що вам все одно потрібно використовувати EventCounters для отримання лічильників із нижчих рівнів стеку, таких як System.Net.Sockets. Хоча всі вбудовані лічильники подій, які існували в попередніх версіях, все ще підтримуються, команда .NET не очікує значних нових інвестицій у лічильники подій, і нові вбудовані інструменти будуть додані, використовуючи System.Diagnostics.Metrics, в майбутніх версіях.
Щоб отримати додаткові відомості про використання вбудованих метрик HTTP, прочитайте наш підручник щодо мережевих метрик у .NET . Він містить приклади збирання та звітування за допомогою Prometheus і Grafana, а також демонструє, як збагачувати та тестувати вбудовані HTTP-метрики. Щоб отримати вичерпний список вбудованих інструментів, перегляньте документацію для метрик System.Net . Якщо вас більше цікавить серверна сторона, будь ласка, прочитайте документацію про показники ASP.NET Core.
Розширена телеметрія
Окрім нових показників, наявні телеметричні події EventSource, представлені в .NET 5, були доповнені додатковою інформацією про HTTP-з’єднання ( dotnet/runtime#88853 ):
Тепер, коли встановлюється нове з’єднання, подія логує connectionId разом із схемою, портом та IP-адресою однорангового пристрою. Це дає змогу співвідносити запити та відповіді зі з’єднаннями через подію RequestHeadersStart, яка виникає, коли запит пов’язується з об’єднаним з’єднанням і починає оброблятися, яка також реєструє пов’язані connectionId. Це особливо цінно в діагностичних сценаріях, коли користувачі хочуть бачити IP-адреси серверів, які обслуговують їхні HTTP-запити, що було основною мотивацією додавання ( dotnet/runtime#63159 ).
Події можна використовувати багатьма способами, див. Мережева телеметрія в .NET – Події . Але для покращеного журналювання під час процесу EventListener можна використовувати спеціальний параметр, щоб співвіднести пару запит/відповідь із даними підключення:
Крім того, подію Redirect було розширено, щоб включити URI перенаправлення:
-void Redirect();
+void Redirect(string redirectUri);
Коди помилок HTTP
Одна з проблем діагностики HttpClient полягала в тому, що у випадку винятку було непросто програмно визначити точну причину помилки. Єдиним способом відрізнити багато з них було розібрати повідомлення про винятки з HttpRequestException. Крім того, інші реалізації HTTP, такі як WinHTTP із кодами помилок ERROR_WINHTTP_*, пропонують такі функції у формі числових кодів або перерахувань. Отже, .NET 8 представляє подібний перелік і надає його у винятках, створених обробкою HTTP, які є:
– HttpRequestException для обробки запиту до отримання заголовків відповіді.
– HttpIOException для читання змісту відповіді.
Дизайн HttpRequestError enum і те, як він підключається до винятків HTTP, описано в пропозиції API dotnet/runtime#76644 .
Тепер споживач методів HttpClient може обробляти конкретні внутрішні помилки набагато легше та надійніше:
Підтримка проксі HTTPS
Однією з особливо затребуваних функцій, яку було реалізовано в цьому випуску, є підтримка HTTPS-проксі ( dotnet/runtime#31113). Тепер можна використовувати проксі, які обслуговують запити через HTTPS, тобто з’єднання з проксі є безпечним. Це нічого не говорить про сам запит від проксі, який може бути як HTTP, так і HTTPS. У випадку звичайного текстового HTTP-запиту з’єднання з проксі-сервером HTTPS є безпечним (через HTTPS), а потім іде простий текстовий запит від проксі-сервера до пункту призначення. У разі запиту HTTPS (тунель проксі) початковий запит CONNECT на відкриття тунелю буде надіслано через захищений канал (HTTPS) до проксі, а потім запит HTTPS від проксі до пункту призначення через тунель.
Щоб скористатися цією функцією, все, що потрібно, це використовувати схему HTTPS під час налаштування проксі:
HttpClientFactory
.NET 8 розширює можливості налаштування HttpClientFactory, включаючи параметри клієнта за замовчуванням, спеціальне логування та спрощену конфігурацію SocketsHttpHandler. API реалізовано в пакеті Microsoft.Extensions.Http, який доступний на NuGet і включає підтримку .NET Standard 2.0. Таким чином, цю функцію можна використовувати клієнтам не лише в .NET 8, але й у всіх версіях .NET, включаючи .NET Framework (єдиним винятком є відповідні API SocketsHttpHandler, які доступні лише для .NET 5+).
Налаштуйте параметри за замовчуванням для всіх клієнтів
.NET 8 додає можливість установити конфігурацію за замовчуванням, яка використовуватиметься для всіх HttpClient-ів створених HttpClientFactory( dotnet/runtime#87914). Це корисно, коли всі або більшість зареєстрованих клієнтів містять однакову підмножину конфігурації.
Розглянемо приклад, де визначено два клієнти з іменами, і обидва вони потребують MyAuthHandler для свого ланцюжка обробників повідомлень.
Щоб витягти загальну частину, тепер ви можете використовувати метод ConfigureHttpClientDefaults:
Усі методи розширення IHttpClientBuilder, які використовуються з AddHttpClient також можна використовувати всередині .ConfigureHttpClientDefaults.
Конфігурація за замовчуванням (ConfigureHttpClientDefaults) застосовується до всіх клієнтів перед конфігураціями для конкретного клієнта (AddHttpClient); їх відносне положення в реєстрації не має значення. ConfigureHttpClientDefaults можна зареєструвати кілька разів, у цьому випадку конфігурації будуть застосовані одна за одною в порядку реєстрації. Будь-яка частина конфігурації може бути перевизначена або змінена в конфігураціях для конкретного клієнта, наприклад, ви можете встановити додаткові параметри для об’єкта HttpClient або основного обробника, видалити раніше доданий додатковий обробник тощо.
Зауважте, що з версії 8.0 метод ConfigureHttpMessageHandlerBuilder застарів . Натомість вам слід використовувати методи ConfigurePrimaryHttpMessageHandler(Action<HttpMessageHandler,IServiceProvider>))) або ConfigureAdditionalHttpMessageHandlers, щоб змінити попередньо налаштований основний обробник або список додаткових обробників відповідно.
Змінити логування HttpClient
Налаштування (або навіть просто вимкнення) логування HttpClientFactory було однією з давно запитуваних функцій (dotnet/runtime#77312).
Огляд старого логування
Логування за замовчуванням («старе»), додане HttpClientFactory досить багатослівне і видає 8 повідомлень журналу на запит:
1. Почати сповіщення з URI запиту — перед розповсюдженням через конвеєр обробника делегування;
2. Заголовки запитів — перед пайплайном обробника;
3. Почати сповіщення з URI запиту — після пайплайну обробника;
4. Заголовки запитів — після пайплайну обробника;
5. Зупинити сповіщення з вичерпаним часом — перед розповсюдженням відповіді через конвеєр обробника делегування;
6. Заголовки відповіді — перед тим, як передавати відповідь назад;
7. Зупинити сповіщення з вичерпаним часом — після повернення відповіді;
8. Заголовки відповіді — після передачі відповіді назад.
Це можна проілюструвати схемою нижче. На цій і наступних діаграмах *і [...]позначає подію логування (у реалізації за замовчуванням повідомлення журналу записується в ILogger), і → символізує потік даних через прикладний і транспортний рівні.