跳到主要內容

網路

簡介

Playwright 提供 API 來監控修改瀏覽器網路流量,包括 HTTP 和 HTTPS。頁面執行的任何請求,包括 XHRfetch 請求,都可以被追蹤、修改和處理。

模擬 API

請查看我們的 API 模擬指南,以深入了解如何

  • 模擬 API 請求,永遠不發送 API
  • 執行 API 請求並修改回應
  • 使用 HAR 檔案來模擬網路請求。

網路模擬

您無需進行任何設定即可模擬網路請求。只需定義一個自訂的 Route,為瀏覽器環境模擬網路。

example.spec.ts
import { test, expect } from '@playwright/test';

test.beforeEach(async ({ context }) => {
// Block any css requests for each test in this file.
await context.route(/.css$/, route => route.abort());
});

test('loads page without css', async ({ page }) => {
await page.goto('https://playwright.dev.org.tw');
// ... test goes here
});

或者,您可以使用 page.route() 在單一頁面中模擬網路。

example.spec.ts
import { test, expect } from '@playwright/test';

test('loads page without images', async ({ page }) => {
// Block png and jpeg images.
await page.route(/(png|jpeg)$/, route => route.abort());

await page.goto('https://playwright.dev.org.tw');
// ... test goes here
});

HTTP 驗證

執行 HTTP 驗證。

playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
httpCredentials: {
username: 'bill',
password: 'pa55w0rd',
}
}
});

HTTP Proxy

您可以設定頁面透過 HTTP(S) Proxy 或 SOCKSv5 載入。Proxy 可以設定為整個瀏覽器全域,或針對每個瀏覽器環境個別設定。

您可以選擇性地為 HTTP(S) Proxy 指定使用者名稱和密碼,也可以指定要繞過 proxy 的主機。

以下是全域 Proxy 的範例

playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
proxy: {
server: 'http://myproxy.com:3128',
username: 'usr',
password: 'pwd'
}
}
});

也可以針對每個環境指定

example.spec.ts
import { test, expect } from '@playwright/test';

test('should use custom proxy on a new context', async ({ browser }) => {
const context = await browser.newContext({
proxy: {
server: 'http://myproxy.com:3128',
}
});
const page = await context.newPage();

await context.close();
});

網路事件

您可以監控所有 RequestResponse

// Subscribe to 'request' and 'response' events.
page.on('request', request => console.log('>>', request.method(), request.url()));
page.on('response', response => console.log('<<', response.status(), response.url()));

await page.goto('https://example.com');

或使用 page.waitForResponse() 等待按鈕點擊後的網路回應

// Use a glob URL pattern. Note no await.
const responsePromise = page.waitForResponse('**/api/fetch_data');
await page.getByText('Update').click();
const response = await responsePromise;

變化

使用 page.waitForResponse() 等待 Response

// Use a RegExp. Note no await.
const responsePromise = page.waitForResponse(/\.jpeg$/);
await page.getByText('Update').click();
const response = await responsePromise;

// Use a predicate taking a Response object. Note no await.
const responsePromise = page.waitForResponse(response => response.url().includes(token));
await page.getByText('Update').click();
const response = await responsePromise;

處理請求

await page.route('**/api/fetch_data', route => route.fulfill({
status: 200,
body: testData,
}));
await page.goto('https://example.com');

您可以透過在 Playwright 腳本中處理網路請求來模擬 API 端點。

變化

使用 browserContext.route() 在整個瀏覽器環境或使用 page.route() 在頁面上設定路由。它將適用於彈出視窗和開啟的連結。

await browserContext.route('**/api/login', route => route.fulfill({
status: 200,
body: 'accept',
}));
await page.goto('https://example.com');

修改請求

// Delete header
await page.route('**/*', async route => {
const headers = route.request().headers();
delete headers['X-Secret'];
await route.continue({ headers });
});

// Continue requests as POST.
await page.route('**/*', route => route.continue({ method: 'POST' }));

您可以繼續修改請求。上面的範例從傳出的請求中移除 HTTP 標頭。

中止請求

您可以使用 page.route()route.abort() 中止請求。

await page.route('**/*.{png,jpg,jpeg}', route => route.abort());

// Abort based on the request type
await page.route('**/*', route => {
return route.request().resourceType() === 'image' ? route.abort() : route.continue();
});

修改回應

若要修改回應,請使用 APIRequestContext 取得原始回應,然後將回應傳遞給 route.fulfill()。您可以透過選項覆寫回應上的個別欄位

await page.route('**/title.html', async route => {
// Fetch original response.
const response = await route.fetch();
// Add a prefix to the title.
let body = await response.text();
body = body.replace('<title>', '<title>My prefix:');
await route.fulfill({
// Pass all fields from the response.
response,
// Override response body.
body,
// Force content type to be html.
headers: {
...response.headers(),
'content-type': 'text/html'
}
});
});

Glob URL 模式

Playwright 在網路攔截方法(如 page.route()page.waitForResponse())中使用簡化的 glob 模式進行 URL 比對。這些模式支援基本萬用字元

  1. 星號
    • 單個 * 符號比對除了 / 以外的任何字元
    • 雙個 ** 符號比對包括 / 在內的任何字元
  2. 問號 ? 比對除了 / 以外的任何單個字元
  3. 大括號 {} 可用於比對以逗號 , 分隔的選項列表

範例

  • https://example.com/*.js 比對 https://example.com/file.js,但不比對 https://example.com/path/file.js
  • **/*.js 比對 https://example.com/file.jshttps://example.com/path/file.js
  • **/*.{png,jpg,jpeg} 比對所有圖片請求

重要注意事項

  • glob 模式必須比對整個 URL,而不僅僅是部分 URL。
  • 當使用 glob 進行 URL 比對時,請考慮完整的 URL 結構,包括協定和路徑分隔符。
  • 對於更複雜的比對需求,請考慮使用 RegExp 而不是 glob 模式。

WebSockets

Playwright 支援開箱即用的 WebSockets 檢查、模擬和修改。請參閱我們的 API 模擬指南,以了解如何模擬 WebSockets。

每次建立 WebSocket 時,都會觸發 page.on('websocket') 事件。此事件包含 WebSocket 實例,以進行進一步的 web socket 框架檢查

page.on('websocket', ws => {
console.log(`WebSocket opened: ${ws.url()}>`);
ws.on('framesent', event => console.log(event.payload));
ws.on('framereceived', event => console.log(event.payload));
ws.on('close', () => console.log('WebSocket closed'));
});

遺失網路事件和 Service Workers

Playwright 的內建 browserContext.route()page.route() 允許您的測試原生路由請求並執行模擬和攔截。

  1. 如果您正在使用 Playwright 的原生 browserContext.route()page.route(),並且似乎遺失了網路事件,請將 serviceWorkers 設定為 'block' 以停用 Service Workers。
  2. 可能是您正在使用模擬工具,例如 Mock Service Worker (MSW)。雖然此工具開箱即用,可用於模擬回應,但它會新增自己的 Service Worker 來接管網路請求,因此使其對 browserContext.route()page.route() 不可見。如果您對網路測試和模擬都感興趣,請考慮使用內建的 browserContext.route()page.route() 進行 回應模擬
  3. 如果您不僅對使用 Service Workers 進行測試和網路模擬感興趣,而且對路由和監聽 Service Workers 發出的請求感興趣,請參閱 此實驗性功能