From 2c4fccb22d9d66fc1141569f29bb1f4e00bf0b78 Mon Sep 17 00:00:00 2001 From: Sergey Karmanov Date: Mon, 12 Oct 2026 14:13:51 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BrowserScripts/MicrosoftLoginHelper.cs | 11 ++++++---- src/Services/MicrosoftAuthService.cs | 25 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/BrowserScripts/MicrosoftLoginHelper.cs b/src/BrowserScripts/MicrosoftLoginHelper.cs index 6070e10..bd4f0ae 100644 --- a/src/BrowserScripts/MicrosoftLoginHelper.cs +++ b/src/BrowserScripts/MicrosoftLoginHelper.cs @@ -16,11 +16,14 @@ public static class MicrosoftLoginHelper { logger.LogInformation("Начало входа в Microsoft. Url: {LoginUrl}, пользователь: {Username}", loginUrl, username); - await page.GotoAsync(loginUrl, new PageGotoOptions { WaitUntil = WaitUntilState.DOMContentLoaded }); + // Готовность формы проверяем ниже по полям: сторонние скрипты могут задерживать DOMContentLoaded. + await page.GotoAsync(loginUrl, new PageGotoOptions { WaitUntil = WaitUntilState.Commit }); - logger.LogDebug("Страница логина загружена, ожидаем переход на домен Microsoft."); + logger.LogDebug("Началась загрузка страницы логина, ожидаем переход на домен Microsoft."); - await page.WaitForURLAsync(new Regex("login\\.(microsoftonline|live)\\.com", RegexOptions.IgnoreCase), new PageWaitForURLOptions { Timeout = 60_000 }); + // WaitForURL при уже совпавшем URL дополнительно ожидает событие загрузки страницы. + await page.WaitForFunctionAsync(@"() => /^login\.(microsoftonline|live)\.com$/i.test(location.hostname)", + options: new PageWaitForFunctionOptions { Timeout = 60_000 }); var useAnotherAccount = page.Locator("div#otherTile, #otherTileText, div[data-test-id='useAnotherAccount']").First; try @@ -35,7 +38,7 @@ public static class MicrosoftLoginHelper } var emailInput = page.Locator("input[name='loginfmt'], input#i0116"); - await emailInput.WaitForAsync(new LocatorWaitForOptions { State = WaitForSelectorState.Visible, Timeout = 30_000 }); + await emailInput.WaitForAsync(new LocatorWaitForOptions { State = WaitForSelectorState.Visible, Timeout = 60_000 }); logger.LogDebug("Поле ввода email найдено, вводим логин."); await emailInput.FillAsync(username); diff --git a/src/Services/MicrosoftAuthService.cs b/src/Services/MicrosoftAuthService.cs index abde723..523ea44 100644 --- a/src/Services/MicrosoftAuthService.cs +++ b/src/Services/MicrosoftAuthService.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using System.Diagnostics; using System.Text.Json; using Microsoft.Playwright; @@ -50,6 +51,19 @@ public class MicrosoftAuthService(ILogger logger, IConfigu ViewportSize = null }); var page = await context.NewPageAsync(); + var pendingRequests = new ConcurrentDictionary(); + EventHandler requestStarted = (_, request) => pendingRequests.TryAdd(request, 0); + EventHandler requestFinished = (sender, request) => pendingRequests.TryRemove(request, out _); + EventHandler requestFailed = (sender, request) => + { + pendingRequests.TryRemove(request, out _); + if (request.Failure == "net::ERR_ABORTED") return; + logger.LogWarning("Ошибка загрузки ресурса браузером. Домен: {Host}, тип: {ResourceType}, причина: {Failure}", + new Uri(request.Url).Host, request.ResourceType, request.Failure); + }; + page.Request += requestStarted; + page.RequestFinished += requestFinished; + page.RequestFailed += requestFailed; try { @@ -80,11 +94,20 @@ public class MicrosoftAuthService(ILogger logger, IConfigu } catch (Exception ex) when (ex is not MicrosoftAuthInProgressException) { - logger.LogError(ex, "Ошибка при получении JWT через Microsoft авторизацию"); + logger.LogError(ex, "Ошибка при получении JWT через Microsoft авторизацию. Текущий домен браузера: {Host}", + page.Url == "about:blank" ? "about:blank" : new Uri(page.Url).Host); + if (!pendingRequests.IsEmpty) + { + var resources = pendingRequests.Keys.Select(request => $"{new Uri(request.Url).Host} ({request.ResourceType})").Distinct(); + logger.LogWarning("Незавершенные запросы браузера: {Resources}", string.Join(", ", resources)); + } throw; } finally { + page.Request -= requestStarted; + page.RequestFinished -= requestFinished; + page.RequestFailed -= requestFailed; await context.CloseAsync(); await browser.CloseAsync();