自定义 HTTP 头:控制浏览器请求头
如何在浏览器引擎级别设置自定义 HTTP 头,以在所有网络请求中实现一致的请求身份。
简介
HTTP 头是浏览器发送的每个请求的组成部分。User-Agent、Accept-Language、Sec-CH-UA 和 Referer 等头构成了浏览器网络身份的重要部分。当这些头与你的指纹配置文件不一致,或者你需要注入用于身份验证和路由的应用特定头时,标准浏览器 API 就力不从心了。
BotBrowser 通过 --bot-custom-headers 标志和 BotBrowser.setCustomHeaders CDP 命令提供引擎级头控制。与在请求形成后拦截的扩展方案不同,BotBrowser 在请求离开浏览器网络栈之前修改头,覆盖所有请求类型,没有时序间隙。
隐私影响
HTTP 头揭示了大量关于你浏览器环境的信息。User-Agent 字符串标识你的浏览器版本和操作系统。Accept-Language 揭示你的语言偏好,并由此推断你可能的地理区域。Client Hints 头(Sec-CH-UA、Sec-CH-UA-Platform、Sec-CH-UA-Mobile)提供关于你浏览器品牌、平台和设备类型的结构化数据。
当这些头与你指纹的其他方面不一致时,这种不一致就很突出。一个报告 Accept-Language: de-DE 但使用美国时区的浏览器,或者 Sec-CH-UA-Platform: "Windows" 但具有 macOS 特定 navigator 属性的浏览器,都会产生追踪系统可以关联的不匹配。
BotBrowser 配置文件自动将所有标准头与配置文件的身份对齐。User-Agent、所有 Sec-CH-UA-* 头和 Accept-Language 都来源于配置文件的浏览器、平台和地区设置。通过 --bot-custom-headers 添加的自定义头扩展了这个基线,而不会干扰配置文件的标准头集。
技术背景
浏览器如何构造请求头
当浏览器发送 HTTP 请求时,它从多个来源构造头:
- 内置头:
User-Agent、Accept、Accept-Encoding、Accept-Language由浏览器引擎根据内部设置添加。 - Client Hints:
Sec-CH-UA、Sec-CH-UA-Mobile、Sec-CH-UA-Platform默认发送。高熵提示如Sec-CH-UA-Full-Version-List仅在服务器通过Accept-CH请求时才发送。 - 应用头:通过 JavaScript 的
fetch()或XMLHttpRequest设置的头。 - 扩展注入的头:浏览器扩展通过
webRequestAPI 添加的头。
这些头的顺序和组成为每个浏览器创建了一致的模式。Chrome、Edge 和 Firefox 各自产生不同的头排序和组合。
基于配置文件的头一致性
当 BotBrowser 加载指纹配置文件时,它配置所有标准头以匹配配置文件的身份:
User-Agent匹配配置文件的浏览器版本和平台Sec-CH-UA包含正确顺序的品牌令牌Sec-CH-UA-Platform匹配配置文件的操作系统Accept-Language反映配置的地区和语言偏好
这些头在引擎级别设置,适用于所有请求,包括初始导航请求、子资源加载和 JavaScript 发起的请求。不存在可能观察到错误头的时序间隙。
自定义头与标准头
自定义头(以 X- 开头或应用特定名称的头)与标准头有不同的用途。它们携带应用特定的数据:身份验证令牌、会话标识符、应用版本标记或路由提示。BotBrowser 的 --bot-custom-headers 标志添加这些自定义头而不修改配置文件管理的标准头。
常见方案及其局限性
基于扩展的头修改
浏览器扩展可以通过 webRequest.onBeforeSendHeaders API 修改头。这种方案有几个缺点:
- 时序问题:第一个请求(导航请求)可能在扩展的监听器完全注册之前触发
- 覆盖不完整:Service Worker 请求、CORS 预检请求和一些内部请求可能不会触发扩展的监听器
- 可检测的痕迹:修改头的扩展在浏览器的扩展 API 表面留下痕迹
- 性能开销:每个请求都通过扩展的 JavaScript 处理程序,增加了延迟
基于 CDP 的头覆盖
Puppeteer 和 Playwright 通过 CDP 提供头覆盖 API:
// Puppeteer - 有限的方案
await page.setExtraHTTPHeaders({ 'X-Custom': 'value' });
这对页面级头有效,但有局限性:
- 这种方式设置的头仅适用于特定页面
- Service Worker 和共享 Worker 可能不会收到自定义头
- CDP 的
Network.setExtraHTTPHeaders命令需要Network.enable,这本身可能影响指纹追踪
JavaScript Fetch/XHR 头
在单个 fetch() 或 XMLHttpRequest 调用上设置头只覆盖 JavaScript 发起的请求。导航请求、图片加载、样式表获取和其他浏览器发起的请求不被覆盖。
BotBrowser 的方案
--bot-custom-headers 标志
BotBrowser 的 --bot-custom-headers 标志(PRO)在浏览器引擎级别注入自定义头:
chrome --bot-profile="/path/to/profile.enc" \
--bot-custom-headers='{"X-Custom-Header":"value","X-Auth-Token":"abc123"}' \
--user-data-dir="$(mktemp -d)"
由于修改发生在 Chromium 网络栈内部,自定义头被添加到:
- 初始导航请求
- 子资源请求(图片、脚本、样式表、字体)
- XHR 和 Fetch API 请求
- WebSocket 升级请求
- Service Worker 请求
没有时序间隙,没有遗漏的请求类型。
BotBrowser.setCustomHeaders CDP 命令
对于运行时头管理,BotBrowser 提供了一个可以发送到浏览器级会话的 CDP 命令:
Puppeteer:
const cdpSession = await browser.target().createCDPSession();
await cdpSession.send('BotBrowser.setCustomHeaders', {
headers: { 'x-requested-with': 'com.example.app' }
});
Playwright:
const cdpSession = await browser.newBrowserCDPSession();
await cdpSession.send('BotBrowser.setCustomHeaders', {
headers: { 'x-requested-with': 'com.example.app' }
});
重要提示:此命令必须发送到浏览器级 CDP 会话,而非页面级会话。发送到页面目标会返回 ProtocolError: 'BotBrowser.setCustomHeaders' wasn't found。
配置文件级别配置
自定义头也可以在配置文件的 configs.customHeaders 中设置。当你希望头嵌入到配置文件本身而非在启动时指定时,这很有用。
配置和用法
使用自定义头的 CLI 设置
chrome --bot-profile="/path/to/profile.enc" \
--bot-custom-headers='{"X-App-Version":"2.1.0","X-Session-ID":"sess_abc123"}' \
--proxy-server=socks5://user:pass@proxy:1080 \
--user-data-dir="$(mktemp -d)"
Playwright 集成
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-custom-headers={"X-Auth":"token123","X-Client":"webapp"}',
],
headless: true,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
await browser.close();
})();
Puppeteer 集成
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-custom-headers={"X-Auth":"token123"}',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
})();
JavaScript 引号处理
从 JavaScript 传递 --bot-custom-headers 时,不要在值内包含 shell 风格的引号:
// 正确
const headers = { 'X-Custom': 'value', 'X-Auth': 'token' };
args.push('--bot-custom-headers=' + JSON.stringify(headers));
// 错误 - 单引号会成为 JSON 值的一部分
args.push(`--bot-custom-headers='${JSON.stringify(headers)}'`);
通过 CDP 运行时更新头
对于需要在会话期间更改自定义头的工作流:
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
});
const cdpSession = await browser.newBrowserCDPSession();
// 设置初始头
await cdpSession.send('BotBrowser.setCustomHeaders', {
headers: { 'x-requested-with': 'com.example.app' }
});
const page = await (await browser.newContext()).newPage();
await page.goto('https://example.com');
// 会话中途更新头
await cdpSession.send('BotBrowser.setCustomHeaders', {
headers: { 'x-requested-with': 'com.example.app', 'x-session': 'refreshed' }
});
await page.goto('https://example.com/dashboard');
await browser.close();
})();
验证
启动带有自定义头的 BotBrowser 后,验证它们是否已应用:
- 打开一个会回显请求头的页面(如 httpbin.org/headers)
- 确认你的自定义头出现在响应中
- 检查 DevTools 中的 Network 面板,查看所有请求类型上的头
- 验证标准头(User-Agent、Sec-CH-UA)仍与配置文件匹配
const page = await context.newPage();
await page.goto('https://httpbin.org/headers');
const headersText = await page.textContent('body');
console.log('Request headers:', headersText);
最佳实践
-
静态头使用 --bot-custom-headers。 如果头在会话期间不变,CLI 标志比 CDP 更简单。
-
动态头使用 BotBrowser.setCustomHeaders。 当头需要在会话期间更改(例如轮换认证令牌)时,使用 CDP 命令。
-
不要覆盖配置文件管理的头。 自定义头应添加新头,而不替换 User-Agent 或 Sec-CH-UA。覆盖配置文件头会造成不一致。
-
避免使用常见的扩展头名称。 如
X-Forwarded-For或X-Real-IP等头可能与代理基础设施冲突。使用应用特定的名称。 -
使用 httpbin.org/headers 进行测试。 此端点会回显所有收到的头,便于验证你的配置。
-
setCustomHeaders 始终使用浏览器级 CDP 会话。 页面级会话会返回错误,因为该命令在浏览器级别运行。
常见问题
自定义头是应用于所有请求还是仅导航请求? 所有请求。BotBrowser 在引擎级别应用自定义头,覆盖导航、子资源、XHR、Fetch、WebSocket 和 Service Worker 请求。
我可以为每个上下文设置不同的自定义头吗?
--bot-custom-headers 标志应用于所有上下文。对于每上下文的头,使用 BotBrowser.setCustomHeaders CDP 命令,可以在上下文操作之间更新。
自定义头是否影响指纹?
不属于标准浏览器头集的自定义头(如 X-Custom-Header)不影响浏览器指纹。它们只是请求中的附加头。
我可以删除标准头吗? BotBrowser 不支持通过自定义头删除标准头。配置文件管理的头始终包含,以维护指纹一致性。
--bot-custom-headers 是否与 --proxy-server 配合使用? 是的。无论是否配置代理,自定义头都会添加到请求中。代理看到完整的头集。
我可以设置的自定义头数量有上限吗? 没有特定限制。然而,过大的头集会增加请求大小,可能触发服务端限制。
我可以用 --bot-custom-headers 设置 Cookie 头吗?
对于 Cookie 管理,请使用专用的 --bot-cookies 标志。它提供带有域名作用域和过期时间的正确 Cookie 处理。
总结
HTTP 头控制对于维护一致的浏览器身份至关重要。BotBrowser 通过配置文件(标准头)、--bot-custom-headers 标志(静态自定义头)和 BotBrowser.setCustomHeaders CDP 命令(动态运行时头)提供引擎级头管理。这些工具结合使用,确保每个请求都携带一致、完整的头信息。
相关网络配置请参阅代理配置和User-Agent 控制和 Client Hints。多账户身份管理请参阅多账户浏览器隔离。