Mục lục
- Mục Tiêu Bài Học
- Cấu Trúc Object
proxy - Config Mức Global
- Use Case Proxy
- Proxy Với MITM Tool
- Per-Context Proxy vs Launch Proxy
- Multi-Project Proxy
ignoreHTTPSErrors— Bỏ Qua TLS Error- Pattern Local HTTPS Dev
- Phân Biệt
ignoreHTTPSErrorsvsclientCertificates - Performance Overhead & Limitations
- 4 Pitfalls
- Quiz + Bài Tiếp
Mục Tiêu Bài Học
- Nắm cấu trúc đầy đủ của
proxyobject:server,username,password,bypass. - Phân biệt proxy đặt ở
launchOptions.proxy(toàn browser) vớiuse.proxy(per-context). - Áp dụng
proxycho 3 use case thực tế: corporate network, debug traffic MITM, geo-test. - Hiểu vai trò của
ignoreHTTPSErrorsvà khi nào nên — không nên — bật option này. - Nhận biết sự khác biệt giữa
ignoreHTTPSErrorsvàclientCertificates[v1.45+]. - Cấu hình multi-project để chạy cùng test suite qua proxy và không qua proxy.
- Nhận biết 4 pitfall phổ biến và limitation kỹ thuật của
proxy.
Cấu Trúc Object proxy
interface ProxyConfig {
server: string; // URL proxy — HTTP, HTTPS, hoặc SOCKS5 (bắt buộc)
username?: string; // Proxy authentication username
password?: string; // Proxy authentication password
bypass?: string; // Comma-separated hostname patterns bỏ qua proxy
}
server
Field bắt buộc duy nhất. Định dạng URL đầy đủ bao gồm scheme và port:
// HTTP proxy
proxy: { server: 'http://proxy.example.com:8080' }
// HTTPS proxy (tunnel TLS)
proxy: { server: 'https://proxy.example.com:8443' }
// SOCKS5 proxy
proxy: { server: 'socks5://10.0.0.1:1080' }
Playwright forward tất cả request của context qua proxy này — bao gồm navigation, XHR, fetch, WebSocket (có giới hạn, xem bài 11).
username và password
Hai field optional, dùng khi proxy yêu cầu authentication. Nếu proxy có auth mà bỏ qua hai field này, browser sẽ nhận 407 Proxy Authentication Required và request fail — thường silent fail không có error message rõ ràng trong test output.
proxy: {
server: 'http://proxy.corp.example.com:8080',
username: 'corp-user',
password: 'corp-pass',
}
Với SOCKS5, không encode username/password vào URL (ví dụ socks5://user:pass@host:port) — Playwright không parse credentials từ URL SOCKS5. Phải dùng field username / password riêng.
bypass
Comma-separated string chứa hostname patterns không đi qua proxy. Hữu ích để tránh internal request bị chặn hoặc chậm do đi qua proxy không cần thiết:
proxy: {
server: 'http://proxy.example.com:8080',
bypass: 'localhost,127.0.0.1,*.internal,10.*',
}
Patterns dùng glob đơn giản — * match bất kỳ chuỗi nào. Không hỗ trợ regex. Không hỗ trợ CIDR notation (10.0.0.0/8) — phải viết pattern hostname (10.*).
Config Mức Global
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
proxy: {
server: 'http://proxy.example.com:8080',
username: 'user',
password: 'pass',
bypass: 'localhost,*.internal',
},
ignoreHTTPSErrors: true,
},
});
Khi đặt trong use global, mọi context trong mọi test của toàn project đều dùng proxy này. bypass: 'localhost,*.internal' đảm bảo request tới localhost và các domain *.internal đi thẳng không qua proxy — tránh vòng lặp hoặc timeout khi test local server.
Use Case Proxy
Corporate network
Môi trường doanh nghiệp thường bắt buộc mọi outbound request đi qua corporate proxy. Playwright không tự đọc hệ thống proxy của OS — phải khai báo tường minh trong config:
use: {
proxy: {
server: 'http://proxy.corp.example.com:8080',
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS,
bypass: 'localhost,*.corp.internal',
},
}
Đặt credentials trong biến môi trường (process.env) thay vì hardcode vào file config.
Capture traffic qua MITM tool
Burp Suite, Charles Proxy, mitmproxy đều hoạt động như một local proxy — Playwright forward traffic qua đó để inspect, modify hoặc log request/response. Xem chi tiết ở bài 5.
Geo-test — IP từ quốc gia khác
Một số site trả nội dung khác nhau tùy IP location (giá hiển thị theo đồng tiền địa phương, content bị geo-block, redirect theo country). Dùng proxy IP tại quốc gia đó để test hành vi site khi detect IP location:
// Chạy test như request đến từ IP tại Nhật Bản
use: {
proxy: { server: 'http://jp-proxy.example.com:8080' },
}
Lưu ý: đây là IP-based geo-test, không phải locale/timezone emulation (đã cover bài 9). Hai cơ chế hoạt động ở tầng khác nhau — proxy thay đổi IP thật của request; locale/timezone chỉ thay đổi dữ liệu browser API.
Proxy Với MITM Tool
Ba công cụ phổ biến nhất để intercept HTTP/HTTPS traffic khi debug:
- Burp Suite: mặc định port
8080. - Charles Proxy: mặc định port
8888. - mitmproxy: mặc định port
8080.
Config Playwright trỏ vào tool đang chạy local:
// Dùng với Burp Suite / mitmproxy
use: {
proxy: { server: 'http://127.0.0.1:8080' },
ignoreHTTPSErrors: true, // Cần thiết vì tool tự inject cert riêng
}
// Dùng với Charles Proxy
use: {
proxy: { server: 'http://127.0.0.1:8888' },
ignoreHTTPSErrors: true,
}
ignoreHTTPSErrors: true cần thiết ở đây vì MITM tool decrypt HTTPS bằng cách present cert của chính nó thay cert thật của server — browser sẽ báo cert không hợp lệ nếu không bật option này.
Workflow debug: chạy Burp / Charles trước, enable intercept, sau đó chạy Playwright test — toàn bộ request sẽ xuất hiện trong tool để inspect body, header, response.
Per-Context Proxy vs Launch Proxy
Playwright hỗ trợ đặt proxy ở hai tầng:
launchOptions.proxy: apply cho toàn bộ browser process — mọi context trong browser đó đều dùng chung một proxy. Không thể override per-context.use.proxy(fixture option): apply ở tầng BrowserContext — mỗi context có thể dùng proxy khác nhau. Đây là cách linh hoạt hơn khi cần nhiều proxy khác nhau trong cùng test suite.
// launchOptions.proxy — toàn browser, không thể override per-context
export default defineConfig({
use: {
launchOptions: {
proxy: { server: 'http://proxy.example.com:8080' },
},
},
});
// use.proxy — per-context, có thể override trong test.use()
export default defineConfig({
use: {
proxy: { server: 'http://proxy.example.com:8080' },
},
});
Khi dùng use.proxy, override trong test cụ thể bằng test.use():
test.describe('via different proxy', () => {
test.use({
proxy: { server: 'http://other-proxy.example.com:3128' },
});
test('request goes through other-proxy', async ({ page }) => {
await page.goto('https://httpbin.org/ip');
// IP sẽ là IP của other-proxy
});
});
Multi-Project Proxy
Dùng Playwright projects để chạy cùng test suite trong hai mode: kết nối trực tiếp và kết nối qua proxy. Hữu ích để xác nhận hành vi không thay đổi khi traffic đi qua proxy, hoặc để tách test geo-specific:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'direct',
use: {
// Không proxy — kết nối trực tiếp
},
},
{
name: 'via-proxy',
use: {
proxy: {
server: 'http://proxy.example.com:8080',
bypass: 'localhost',
},
},
},
{
name: 'jp-geo',
use: {
proxy: { server: 'http://jp-proxy.example.com:8080' },
locale: 'ja-JP',
timezoneId: 'Asia/Tokyo',
},
testMatch: '**/geo/**/*.spec.ts',
},
],
});
Chạy chỉ một project cụ thể:
npx playwright test --project=via-proxy
ignoreHTTPSErrors — Bỏ Qua TLS Error
ignoreHTTPSErrors: true bảo browser chấp nhận TLS certificate dù:
- Cert tự ký (self-signed) — không có CA đáng tin cậy ký.
- Cert hết hạn (expired).
- Hostname không khớp với cert (CN/SAN mismatch).
- Cert từ CA nội bộ (internal CA) chưa được install vào OS trust store.
Mặc định (false), Playwright throw net::ERR_CERT_* hoặc tương đương khi gặp TLS error — test fail ngay tại page.goto().
// Bật ignoreHTTPSErrors
use: {
ignoreHTTPSErrors: true,
}
Khi nào nên bật: test staging/dev với cert tự ký, local HTTPS server (Vite, Next.js dev mode với self-signed cert), hoặc khi dùng MITM tool debug (Burp/Charles inject cert riêng).
Khi nào không nên bật: test production. Nếu bật trên production, test sẽ pass dù cert thực sự bị misconfigure — mask bug cert mà user thật sẽ gặp trên trình duyệt thường.
Pattern Local HTTPS Dev
Khi dev server chạy HTTPS local với cert tự ký (ví dụ Vite HTTPS mode, Next.js với --experimental-https, hoặc mkcert chưa install vào trust store):
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://localhost:3000',
ignoreHTTPSErrors: true, // Self-signed cert — local dev chỉ
},
});
Nếu dùng mkcert và đã chạy mkcert -install để install CA vào hệ thống, Chromium thường tin tưởng cert đó mà không cần ignoreHTTPSErrors. Chỉ cần bật option này khi cert thực sự không có trong trust store của browser.
Pattern tách staging vs production:
export default defineConfig({
projects: [
{
name: 'staging',
use: {
baseURL: 'https://staging.example.com',
ignoreHTTPSErrors: true, // Staging dùng self-signed cert nội bộ
},
},
{
name: 'production',
use: {
baseURL: 'https://www.example.com',
// ignoreHTTPSErrors KHÔNG đặt — production cert phải hợp lệ
},
},
],
});
Phân Biệt ignoreHTTPSErrors vs clientCertificates
Hai option này xử lý hai chiều TLS khác nhau và dễ nhầm:
| Option | Chiều | Mục đích |
|---|---|---|
ignoreHTTPSErrors |
Server → Client | Browser bỏ qua lỗi khi xác thực cert của server |
clientCertificates [v1.45+] |
Client → Server | Browser gửi cert của client để server xác thực (mTLS) |
ignoreHTTPSErrorschỉ ảnh hưởng đến việc browser có trust cert của server không — không liên quan gì đến cert của client.clientCertificatesdùng cho mutual TLS (mTLS): server yêu cầu client cũng phải present certificate để authenticate. Use case: API gateway bảo mật, internal service mesh.
clientCertificates là topic riêng — không thuộc nhóm option fixture này, sẽ được cover ở chương C chuyên về TLS và security testing.
Performance Overhead & Limitations
Performance overhead
Mỗi request phải thiết lập kết nối tới proxy trước khi forward đến server đích. Overhead phụ thuộc vào latency network giữa CI runner và proxy server:
- Proxy local (127.0.0.1): overhead nhỏ, thường < 5 ms.
- Proxy nội bộ cùng datacenter: 5–50 ms.
- Proxy remote khác region: 50–500 ms per request.
- SOCKS5 chậm hơn HTTP proxy khoảng 10–20% do overhead giao thức — đặc biệt rõ khi có nhiều request nhỏ.
Với test suite nhiều request, proxy remote có thể làm tăng tổng thời gian chạy đáng kể. Nên đặt timeout cao hơn mặc định khi dùng proxy xa:
use: {
proxy: { server: 'http://remote-proxy.example.com:8080' },
navigationTimeout: 60_000, // Tăng từ mặc định 30s
actionTimeout: 30_000,
}
Limitations
- WebSocket qua SOCKS5: không ổn định trên một số SOCKS5 proxy implementation — WebSocket upgrade có thể bị block hoặc fail. HTTP proxy (CONNECT tunnel) xử lý WebSocket tốt hơn.
bypasskhông hỗ trợ regex: chỉ glob đơn giản với*. Không thể viết pattern phức tạp như10\.\d+\.\d+\.\d+.- Proxy authentication challenge popup: một số proxy trả về HTML form để user nhập credentials thay vì HTTP 407. Playwright không tự dismiss form đó — phải kèm
username/passwordtrong config để proxy nhận Basic Auth header và không hiện form. - Không đọc system proxy: Playwright không kế thừa proxy từ biến môi trường hệ thống (
HTTP_PROXY,HTTPS_PROXY). Phải khai báo tường minh trong config hoặc quaprocess.env.
4 Pitfalls
Pitfall 1 — ignoreHTTPSErrors: true trên production test
// Nguy hiểm — không phân biệt staging và production
export default defineConfig({
use: {
ignoreHTTPSErrors: true, // Global cho cả production
},
});
Hệ quả: cert production bị expired hoặc misconfigure, test vẫn pass. User thật trên trình duyệt thường sẽ nhận ERR_CERT_* và không thể truy cập. Bug này bị mask hoàn toàn bởi option trên.
Fix: chỉ bật ignoreHTTPSErrors trong project staging/dev, không đặt ở global hoặc production project.
Pitfall 2 — Quên bypass cho localhost
// Thiếu bypass — mọi request kể cả localhost đều đi qua proxy
use: {
proxy: {
server: 'http://proxy.corp.example.com:8080',
// Thiếu: bypass: 'localhost,127.0.0.1'
},
}
Hệ quả: request tới baseURL: 'http://localhost:3000' đi qua corporate proxy — proxy không route được internal address → connection timeout hoặc 502. Test fail với lỗi timeout khó debug.
Fix: luôn thêm bypass: 'localhost,127.0.0.1' (hoặc rộng hơn 'localhost,127.0.0.1,*.internal') khi test local server.
Pitfall 3 — Proxy auth fail silent
use: {
proxy: {
server: 'http://proxy.corp.example.com:8080',
// Thiếu username/password khi proxy yêu cầu auth
},
}
Hệ quả: proxy trả 407, browser không tự retry với credentials vì không có. Request fail — nhưng lỗi thường xuất hiện dưới dạng net::ERR_TUNNEL_CONNECTION_FAILED hoặc navigation timeout thay vì message "proxy auth failed". Mất thời gian debug.
Fix: kiểm tra proxy có yêu cầu auth không, nếu có thì khai báo username/password.
Pitfall 4 — SOCKS5 auth qua URL format
// Sai — Playwright không parse credentials từ SOCKS5 URL
use: {
proxy: {
server: 'socks5://myuser:[email protected]:1080',
},
}
// Đúng — dùng field riêng
use: {
proxy: {
server: 'socks5://socks-proxy.example.com:1080',
username: 'myuser',
password: 'mypass',
},
}
HTTP proxy có thể parse credentials từ URL (một số implementation), nhưng SOCKS5 không. Để an toàn, luôn dùng field username/password tách biệt cho cả hai loại.
Quiz + Bài Tiếp
Quiz
-
Config sau có vấn đề gì?
use: { proxy: { server: 'socks5://user:[email protected]:1080', }, }Đáp án
Playwright không parse credentials từ SOCKS5 URL.
user:passtrong URL sẽ bị bỏ qua. Phải tách ra:server: 'socks5://10.0.0.1:1080',username: 'user',password: 'pass'. -
Test đang dùng
baseURL: 'https://localhost:3000'và proxy corporate. Sau khi thêm proxy config, test bị timeout. Nguyên nhân có thể là gì?Đáp án
Request tới
localhostđang đi qua proxy corporate — proxy không thể route địa chỉ localhost của máy CI. Fix: thêmbypass: 'localhost,127.0.0.1'vào proxy config. -
ignoreHTTPSErrors: truecó bỏ qua lỗi khi cert của client bị reject bởi server không?Đáp án
Không.
ignoreHTTPSErrorschỉ bỏ qua lỗi khi browser xác thực cert của server (chiều server → client). Nếu server yêu cầu client cert (mTLS) và client không có, đó là vấn đề khác — cần dùngclientCertificates[v1.45+]. -
Pattern
bypass: '10.*'có cover địa chỉ10.10.20.5không?Đáp án
Có —
*trong bypass match bất kỳ chuỗi nào, bao gồm chuỗi có dấu chấm.10.*match10.0.0.1,10.10.20.5, v.v. Tuy nhiên không hỗ trợ CIDR như10.0.0.0/8. -
Sự khác biệt giữa đặt proxy ở
launchOptions.proxyvàuse.proxylà gì?Đáp án
launchOptions.proxyapply cho toàn bộ browser process — không thể override per-context.use.proxyapply ở tầng BrowserContext — có thể override bằngtest.use()trong describe block cụ thể, cho phép các context khác nhau dùng proxy khác nhau.
Bài Tiếp
Bài 19: Cú Pháp test.extend() — mở đầu chương A.3 Custom Fixtures: cách tạo fixture riêng với test.extend(), lifecycle setup/teardown, và scope fixture.
Tài liệu tham khảo
- Playwright Docs — BrowserContext proxy option
- Playwright Docs — BrowserContext ignoreHTTPSErrors option
- Playwright Docs — Network: HTTP Proxy
- Playwright Docs — APIRequestContext proxy option
- Playwright Release Notes v1.45 — clientCertificates
- Burp Suite — Proxy Setup
- Charles Proxy — SSL Proxying
- mitmproxy — How mitmproxy works
