Сеть
Введение
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(). Эти шаблоны поддерживают базовые подстановочные символы:
- Звёздочки:
- Одна
*соответствует любым символам, кроме/ - Двойная
**соответствует любым символам, включая/
- Одна
- Знак вопроса
?соответствует только знаку вопроса?. Если вы хотите сопоставить любой символ, используйте*вместо этого. - Фигурные скобки
{}могут использоваться для сопоставления списка вариантов, разделённых запятыми, - Обратный слеш
\может использоваться для экранирования любого специального символа (обратите внимание, что сам обратный слеш нужно экранировать как\\)
Примеры:
https://example.com/*.jsсоответствуетhttps://example.com/file.js, но не соответствуетhttps://example.com/path/file.jshttps://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() для мокинга ответов.