Перейти к основному содержимому

Сеть

Введение

Playwright предоставляет API для мониторинга и модификации сетевого трафика браузера, как HTTP, так и HTTPS. Любые запросы, которые делает страница, включая XHR и fetch запросы, могут быть отслежены, изменены и обработаны.

Мокирование API

Ознакомьтесь с нашим руководством по мокированию API, чтобы узнать больше о том, как

  • мокировать API-запросы и никогда не обращаться к API
  • выполнять API-запрос и изменять ответ
  • использовать HAR-файлы для мокирования сетевых запросов.

HTTP-аутентификация

Выполнение HTTP-аутентификации.

using var context = await Browser.NewContextAsync(new()
{
HttpCredentials = new HttpCredentials
{
Username = "bill",
Password = "pa55w0rd"
},
});
var page = await context.NewPageAsync();
await page.GotoAsync("https://example.com");

HTTP-прокси

Вы можете настроить страницы для загрузки через HTTP(S)-прокси или SOCKSv5. Прокси может быть установлен глобально для всего браузера или для каждого контекста браузера отдельно.

Вы можете дополнительно указать имя пользователя и пароль для HTTP(S)-прокси, а также указать хосты, которые следует обходить Proxy.

Вот пример глобального прокси:

var proxy = new Proxy
{
Server = "http://myproxy.com:3128",
Username = "user",
Password = "pwd"
};
await using var browser = await BrowserType.LaunchAsync(new()
{
Proxy = proxy
});

Также возможно указать его для каждого контекста:

await using var browser = await BrowserType.LaunchAsync();
await using var context = await browser.NewContextAsync(new()
{
Proxy = new Proxy { Server = "http://myproxy.com:3128" },
});

Сетевые события

Вы можете отслеживать все Request и Response:

using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
page.Request += (_, request) => Console.WriteLine(">> " + request.Method + " " + request.Url);
page.Response += (_, response) => Console.WriteLine("<< " + response.Status + " " + response.Url);
await page.GotoAsync("https://example.com");

Или дождаться сетевого ответа после нажатия кнопки с помощью Page.RunAndWaitForResponseAsync():

// Используйте шаблон URL с глобальными символами
var waitForResponseTask = page.WaitForResponseAsync("**/api/fetch_data");
await page.GetByText("Update").ClickAsync();
var response = await waitForResponseTask;

Вариации

Ожидание Response с Page.RunAndWaitForResponseAsync()

// Используйте регулярное выражение
var waitForResponseTask = page.WaitForResponseAsync(new Regex("\\.jpeg$"));
await page.GetByText("Update").ClickAsync();
var response = await waitForResponseTask;

// Используйте предикат, принимающий объект Response
var waitForResponseTask = page.WaitForResponseAsync(r => r.Url.Contains(token));
await page.GetByText("Update").ClickAsync();
var response = await waitForResponseTask;

Обработка запросов

Вы можете мокировать API-эндпоинты, обрабатывая сетевые запросы в вашем скрипте Playwright.

Вариации

Настройте маршрут для всего контекста браузера с помощью BrowserContext.RouteAsync() или страницы с Page.RouteAsync(). Это будет применяться к всплывающим окнам и открытым ссылкам.

await page.RouteAsync("**/api/fetch_data", async route => {
await route.FulfillAsync(new() { Status = 200, Body = testData });
});
await page.GotoAsync("https://example.com");

Изменение запросов

// Удаление заголовка
await page.RouteAsync("**/*", async route => {
var headers = new Dictionary<string, string>(route.Request.Headers.ToDictionary(x => x.Key, x => x.Value));
headers.Remove("X-Secret");
await route.ContinueAsync(new() { Headers = headers });
});

// Продолжение запросов как POST.
await Page.RouteAsync("**/*", async route => await route.ContinueAsync(new() { Method = "POST" }));

Вы можете продолжать запросы с модификациями. Пример выше удаляет HTTP-заголовок из исходящих запросов.

Прерывание запросов

Вы можете прерывать запросы, используя Page.RouteAsync() и Route.AbortAsync().

await page.RouteAsync("**/*.{png,jpg,jpeg}", route => route.AbortAsync());

// Прерывание на основе типа запроса
await page.RouteAsync("**/*", async route => {
if ("image".Equals(route.Request.ResourceType))
await route.AbortAsync();
else
await route.ContinueAsync();
});

Изменение ответов

Чтобы изменить ответ, используйте APIRequestContext для получения оригинального ответа, а затем передайте ответ в Route.FulfillAsync(). Вы можете переопределить отдельные поля в ответе через опции:

await Page.RouteAsync("**/title.html", async route =>
{
// Получение оригинального ответа.
var response = await route.FetchAsync();
// Добавление префикса к заголовку.
var body = await response.TextAsync();
body = body.Replace("<title>", "<title>My prefix:");

var headers = response.Headers;
headers.Add("Content-Type", "text/html");

await route.FulfillAsync(new()
{
// Передача всех полей из ответа.
Response = response,
// Переопределение тела ответа.
Body = body,
// Принудительное указание типа контента как html.
Headers = headers,
});
});

Шаблоны URL с глобальными символами

Playwright использует упрощённые glob-шаблоны для сопоставления URL в методах перехвата сетевых запросов, таких как Page.RouteAsync() или Page.RunAndWaitForResponseAsync(). Эти шаблоны поддерживают базовые подстановочные символы:

  1. Звёздочки:
    • Одна * соответствует любым символам, кроме /
    • Двойная ** соответствует любым символам, включая /
  2. Знак вопроса ? соответствует только знаку вопроса ?. Если вы хотите сопоставить любой символ, используйте * вместо этого.
  3. Фигурные скобки {} могут использоваться для сопоставления списка вариантов, разделённых запятыми ,
  4. Обратный слеш \ может использоваться для экранирования любого специального символа (обратите внимание, что сам обратный слеш нужно экранировать как \\)

Примеры:

  • https://example.com/*.js соответствует https://example.com/file.js, но не соответствует https://example.com/path/file.js
  • https://example.com/?page=1 соответствует https://example.com/?page=1, но не соответствует https://example.com
  • **/*.js соответствует как https://example.com/file.js, так и https://example.com/path/file.js
  • **/*.{png,jpg,jpeg} соответствует всем запросам изображений

Важные замечания:

  • Шаблон с глобальными символами должен соответствовать всему URL, а не только его части.
  • При использовании шаблонов с глобальными символами для сопоставления URL учитывайте полную структуру URL, включая протокол и разделители пути.
  • Для более сложных требований к сопоставлению рассмотрите возможность использования [RegExp] вместо шаблонов с глобальными символами.

WebSockets

Playwright поддерживает инспекцию, мокирование и модификацию WebSockets из коробки. Ознакомьтесь с нашим руководством по мокированию API, чтобы узнать, как мокировать WebSockets.

Каждый раз, когда создается WebSocket, срабатывает событие Page.WebSocket. Это событие содержит экземпляр WebSocket для дальнейшей инспекции фреймов веб-сокета:

page.WebSocket += (_, ws) =>
{
Console.WriteLine("WebSocket открыт: " + ws.Url);
ws.FrameSent += (_, f) => Console.WriteLine(f.Text);
ws.FrameReceived += (_, f) => Console.WriteLine(f.Text);
ws.Close += (_, ws1) => Console.WriteLine("WebSocket закрыт");
};

Отсутствующие сетевые события и Service Workers

Встроенные методы Playwright — BrowserContext.RouteAsync() и Page.RouteAsync() — позволяют нативно маршрутизировать запросы в тестах и выполнять мокинг и перехват.

Если вы используете нативные BrowserContext.RouteAsync() и Page.RouteAsync(), и при этом кажется, что сетевые события пропадают, отключите Service Workers, установив ServiceWorkers в значение 'block'.

Возможно, вы используете инструмент для моков, например Mock Service Worker (MSW). Он работает «из коробки» для мокинга ответов, но добавляет собственный Service Worker, который перехватывает сетевые запросы, из-за чего они становятся невидимыми для BrowserContext.RouteAsync() и Page.RouteAsync(). Если вам важны и сетевое тестирование, и мокинг, рассмотрите вариант использовать встроенные BrowserContext.RouteAsync() и Page.RouteAsync() для мокинга ответов.